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

Code quality improvements to the TangoShutter Class #847

Closed
wants to merge 23 commits into from

Conversation

HilbertCorsair
Copy link
Contributor

A more formal way to retreve unconventional shutter states from the xml configuration file and add them to the class standard values dictionary with conventional names.

mxcubecore/HardwareObjects/TangoShutter.py Outdated Show resolved Hide resolved
mxcubecore/HardwareObjects/TangoShutter.py Outdated Show resolved Hide resolved
mxcubecore/HardwareObjects/TangoShutter.py Outdated Show resolved Hide resolved
HilbertCorsair and others added 3 commits January 31, 2024 17:20
Co-authored-by: fabcor <fabien.coronis@maxiv.lu.se>
Merging the latest TangoShutter changes : adding logging and some coments
@HilbertCorsair
Copy link
Contributor Author

Just pushed the latest updates. I added logging as well.

@HilbertCorsair
Copy link
Contributor Author

I don't know how relevant this is but, if somene needs to use a list in the xml config file , make sure to use double quotes ("). I copy-pasted the configuration from the comment to the xml file for a test and it had replaced the double quotes (") with simple quotes (') resulting in a json parsing error. No (') are allowed in the json inside the xml ! Only ("). :)

@HilbertCorsair
Copy link
Contributor Author

Just updated the comment section with the example provided by @beteva as well as a warning about using only double quotes.

Copy link
Collaborator

@rhfogh rhfogh left a comment

Choose a reason for hiding this comment

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

I am sorry, but I really, really hate this. I can see that this particular PR is not making the difference; the main point is already merged in, so it is too late. But really:

Putting JSON strings inside XML is bad in itself. But worse, we have here a major change to the configuration system, that has not been discussed as such, and that is only valid for TangoShutters and only implemented inside TangoShutter.py. How are we to keep track of what is happening, if every class uses its own custom configuration system? What happens when someone has to make a new class and looks for examples on how to configure it? What happens if someone else reads inside those XML properties (you are allowed to) and tries to untangle this on his own, maybe to figure out (from the configuration files) what the applicable states for a TangoShutter are?

Supposedly, you can store any data structure you need with XML. It is not very practical, which is why moving to another format seems such a good idea, but while we are agreed on using XML surely the correct procedure is to take the trouble and use XML, not to put in your own hacks.

What I would like to see at this point is either

  1. a proposal for how we are to use JSON-inside-XML as the overall configuration system for MXCuBE in the future, complete with rules for how it is applied and a rationale for why it is a good idea.

or

  1. An explanation for why this is a temporary aberration, and how we can make sure that it will go away again without serving as a pattern for future implementations.

@fabcor-maxiv
Copy link
Contributor

@HilbertCorsair, what was the issue with XML here again? If this can be expressed with XML, this should be expressed with XML. I looked again at the previous pull request, but could not find the rationale why this does not use XML all the way. Did I miss it? Is there a reasoning written down somewhere?

[It might be my fault that we focused on the "eval vs. JSON" topic, instead of focusing on the "why not XML?", and I am sorry for that.]

@elmjag
Copy link
Contributor

elmjag commented Feb 1, 2024

As a side effect for testing this code, we wrote some unit tests for this implementation of TangoShutter:

elmjag@6076956

Fell free to include this into this PR. If that complicates thing to much, I'll make a separate PR in the future.

@HilbertCorsair
Copy link
Contributor Author

I don't like the current configuartion solution either. I'm allready looking into configuration by yaml but this will take some time. I can try a different configuration using only XML. I will test this Monday. Bottom line is that we need a way to mapp any unconventional local tango shutter value : state pare to the conventional states definded in the class. I's not always necesarry and the code doesn't change anything in the configuration of Tango shutters that have conventional values. This is why the values tag in the xml file is optional, as a solution for any shuters with unconventional local tango values (CLOSE instead of CLOSED for example). I don't think there is an issue using just XML for this however if we want to have a general Tango shutter class I don't see an easy way arround have to use 2 configuration sysems (one for shutters with conventional values and one for shutters with unconventional values). The current version does this by importing the json dictionary whenever a shutter has nonconvetional values. I saw this in an example somwhere but I guess we don't neceserly need json.

@fabcor-maxiv
Copy link
Contributor

Oh! But I see now, that this is already done with ast.literal_eval in one of the parent classes:

def initialise_values(self):
"""Initialise the ValueEnum with the values from the config."""
try:
values = ast.literal_eval(self.get_property("values"))
values_dict = dict(**{item.name: item.value for item in self.VALUES})
values_dict.update(values)
self.VALUES = Enum("ValueEnum", values_dict)
except (ValueError, TypeError):
pass

Then we should definitely have stuck to this!

Can we see concrete examples of what we want to write in the XML file that can not be handled by AbstractNState.py already?

@fabcor-maxiv
Copy link
Contributor

If one of the parent classes already uses ast.literal_eval() (AbstractNState), then my recommendation is to also use this in the TangoShutter class (whether the Tango shutter can use the parent method as-is or if it needs to be overridden with some tweaks, I have not understood).

@HilbertCorsair
Copy link
Contributor Author

@fabcor-maxiv Done!

@fabcor-maxiv
Copy link
Contributor

@HilbertCorsair Thanks for your work :)

We plan on testing this latest version tomorrow.

Have you considered adding the basic unit test to this PR?

elmjag added a commit to elmjag/mxcubecore that referenced this pull request Feb 7, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
Some unit tests for checking mxcubecore.HardwareObjects.TangoShutter
shutter hardware object.
@HilbertCorsair
Copy link
Contributor Author

I just added the basic unit test proposed by @elmjag : elmjag/mxcubecore@6076956 . Thanks @fabcor-maxiv

"""


VALUES_JSON = """
Copy link
Contributor

Choose a reason for hiding this comment

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

Please rename this variable to for example VALUES_LITERAL. The VALUES_JSON is now confusing, as technically speaking we are not supporting JSON strings but pythong literal expressions. Event if it so happens in this case that text is identical.

Copy link
Member

@beteva beteva Feb 8, 2024

Choose a reason for hiding this comment

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

Hi @elmjag, I am a bit puzzled that we need a special test for the TangoShutter and not using the generic shutter test. Do we miss something in the generic shutter test or the ShutterMockup. If such is the case, maybe it is worth adding your work to the generic shutter test, so it would serve other shutter types, not just the Tango ones.

Copy link
Contributor

Choose a reason for hiding this comment

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

These are tests to test code in TangoShutter.py. The generic shutter test code does not cover it, as it is using ShutterMockup hardware object.

More specifically these tests set-up an actual tango device and instantiate a TangoShutter hardware object that talks to that device. This way you check that opening/closing shutter work, with TangoShutter hwo, using real tango stack.

They way I read the code in test/pytest/test_shutter.py, it is testing the code in the abstract classes starting with AbstractShutter.

The tests in test_shutter.py and test_hwo_tango_shutter.py are testing related, but separate aspects of the code base.

@elmjag
Copy link
Contributor

elmjag commented Feb 8, 2024

I have tested this PR, it works fine!

Just one addition nitpick comment. Can we please squash all commits in this PR? 20+ commits feels a bit, ahum, noisy in the git history.

@beteva
Copy link
Member

beteva commented Feb 8, 2024

Thank you everybody for the efforts to make the perfect TangoShutter Hardware Object. I think this has been a very useful not only for the TangoShutter, bur also to serve as a model not only for similar hardware objects, which would inherit from AbstractNState, but also for hardware objects, using Tango commands and properties.
Being one of the authors of the AbstractNState, I need to explain what is the idea behind _initialise_values and ast,literal_eval.
The VALUES enum is the one, used by any GUI to set/get the value of the HardwareObject.
In the case of NStates, we expect the particular values, not defined in the AbstractNState class to be defined in the configuration file as a dictionary, with keys being the new name for the enum member and values, which can be of type str, bool, int, float, bur also tuple. We than convert this dictionary to an eval and add it to the already defined members. The dictionary can contain not only new members of the eval, but also redefine the value of already existing ones. For this we use ast.literal_eval and defined the _initialise_values method To make this more clear, here are some real case examples:
<values>{"IN": "BEAM", "OUT": "OFF"}</values> - beamstop
<values>{"IN": False, "OUT": True}</values> - front and back light in/out
<values>{"A30": (1, 30, 0.94), "A15": (2, 15, 0.78)}</values> - aperture (index,size,factor)
We've chosen a tuple because of the conversion to enum, as VALUES is an enum.
Maybe this will make more clear the implementation for the TangoShutter and its parent class.

@marcus-oscarsson
Copy link
Member

I'm happy to merge this but there is a conflict, could you have a look @HilbertCorsair ?

elmjag added a commit to elmjag/mxcubecore that referenced this pull request Mar 22, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Apr 2, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Apr 3, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Apr 3, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Apr 3, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Apr 3, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request May 30, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Jun 11, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Jun 19, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Jun 19, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Jun 19, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Jun 24, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
elmjag added a commit to elmjag/mxcubecore that referenced this pull request Jun 24, 2024
Import all changes from this PR:
mxcube#847

TODO: drop this commit once the PR have been merged, or
      if rejected, deal with it
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.

None yet

6 participants