Repository: pymeasure/pymeasure

Issue:
command_process parameter
During review of PR #376, some doubts were raised about the usefulness of parameter `command_process` in property creation helper methods (https://github.com/pymeasure/pymeasure/pull/376#discussion_r536805762)

The original idea of this parameter is to allow users to process command string before sending to the instrument.

I think, specific use cases needs to be identified and possibly mentioned in user documentation or make a deprecation and eventually remove this parameter


Discussion:
A quick check reveals, that we just use it for a deprecation warning.

I think it might have been useful for channels before we implemented `Channel`.

If we do not find any use case, I'm for deprecating this option.
I don't have an opinion on this, either way is fine by me.
Do you, @msmttchr or @CasperSchippers see any use specific use case?

If not, I'd deprecate the option.
Ok for me to go with deprecation.

Resolving patch:
diff --git a/pymeasure/instruments/common_base.py b/pymeasure/instruments/common_base.py
--- a/pymeasure/instruments/common_base.py
+++ b/pymeasure/instruments/common_base.py
@@ -347,7 +347,7 @@ def control(  # noqa: C901 accept that this is a complex method
         map_values=False,
         get_process=lambda v: v,
         set_process=lambda v: v,
-        command_process=lambda c: c,
+        command_process=None,
         check_set_errors=False,
         check_get_errors=False,
         dynamic=False,
@@ -379,6 +379,10 @@ def control(  # noqa: C901 accept that this is a complex method
             before value mapping, returning the processed value
         :param command_process: A function that takes a command and allows processing
             before executing the command
+
+            .. deprecated:: 0.12
+                Use a dynamic property instead.
+
         :param check_set_errors: Toggles checking errors after setting
         :param check_get_errors: Toggles checking errors after getting
         :param dynamic: Specify whether the property parameters are meant to be changed in
@@ -394,7 +398,7 @@ def control(  # noqa: C901 accept that this is a complex method
         :param dict values_kwargs: Further keyword arguments for :meth:`values`.
         :param \\**kwargs: Keyword arguments for :meth:`values`.
 
-            ..deprecated:: 0.12
+            .. deprecated:: 0.12
                 Use `values_kwargs` dictionary parameter instead.
 
         Example of usage of dynamic parameter is as follows:
@@ -436,6 +440,11 @@ class SpecificInstrument(GenericInstrument):
                  FutureWarning)
             values_kwargs.update(kwargs)
 
+        if command_process is None:
+            command_process = lambda c: c  # noqa: E731
+        else:
+            warn("Do not use `command_process`, use a dynamic property instead.", FutureWarning)
+
         def fget(self,
                  get_command=get_command,
                  values=values,
@@ -518,7 +527,8 @@ def fset(self,
 
     @staticmethod
     def measurement(get_command, docs, values=(), map_values=None,
-                    get_process=lambda v: v, command_process=lambda c: c,
+                    get_process=lambda v: v,
+                    command_process=None,
                     check_get_errors=False, dynamic=False,
                     preprocess_reply=None,
                     separator=',',
@@ -540,6 +550,10 @@ def measurement(get_command, docs, values=(), map_values=None,
             before value mapping, returning the processed value
         :param command_process: A function that take a command and allows processing
             before executing the command, for getting
+
+            .. deprecated:: 0.12
+                Use a dynamic property instead.
+
         :param check_get_errors: Toggles checking errors after getting
         :param dynamic: Specify whether the property parameters are meant to be changed in
             instances or subclasses. See :meth:`control` for an usage example.
@@ -554,7 +568,7 @@ def measurement(get_command, docs, values=(), map_values=None,
         :param dict values_kwargs: Further keyword arguments for :meth:`values`.
         :param \\**kwargs: Keyword arguments for :meth:`values`.
 
-            ..deprecated:: 0.12
+            .. deprecated:: 0.12
                 Use `values_kwargs` dictionary parameter instead.
         """
         if values_kwargs is None:
diff --git a/pymeasure/instruments/toptica/ibeamsmart.py b/pymeasure/instruments/toptica/ibeamsmart.py
--- a/pymeasure/instruments/toptica/ibeamsmart.py
+++ b/pymeasure/instruments/toptica/ibeamsmart.py
@@ -52,6 +52,11 @@ def func(x):
     return func
 
 
+def deprecated_strict_discrete_set(value, values):
+    warn("This property is deprecated, use channels instead.", FutureWarning)
+    return strict_discrete_set(value, values)
+
+
 class DriverChannel(Channel):
     """A laser diode driver channel for the IBeam Smart laser."""
 
@@ -222,12 +227,12 @@ def check_errors(self):
 
         .. deprecated:: 0.12 Use attr:`emission` instead.
         """,
-        validator=strict_discrete_set,
+        validator=deprecated_strict_discrete_set,
         values=[True, False],
         get_process=lambda s: True if s == 'ON' else False,
         set_process=lambda v: "on" if v else "off",
         check_set_errors=True,
-        command_process=_deprecation_warning(
+        preprocess_reply=_deprecation_warning(
             "Property `laser_enabled` is deprecated, use `emission` instead."),
     )
 
@@ -237,12 +242,12 @@ def check_errors(self):
 
         .. deprecated:: 0.12 Use :attr:`ch_1.enabled` instead.
         """,
-        validator=strict_discrete_set,
+        validator=deprecated_strict_discrete_set,
         values=[True, False],
         get_process=lambda s: True if s == 'ON' else False,
         set_process=lambda v: "en 1" if v else "di 1",
         check_set_errors=True,
-        command_process=_deprecation_warning_channels("channel1_enabled"),
+        preprocess_reply=_deprecation_warning_channels("channel1_enabled"),
     )
 
     channel2_enabled = Instrument.control(
@@ -250,12 +255,12 @@ def check_errors(self):
         """Control status of Channel 2 of the laser (bool).
 
         .. deprecated:: 0.12 Use :attr:`ch_2.enabled` instead.""",
-        validator=strict_discrete_set,
+        validator=deprecated_strict_discrete_set,
         values=[True, False],
         get_process=lambda s: True if s == 'ON' else False,
         set_process=lambda v: "en 2" if v else "di 2",
         check_set_errors=True,
-        command_process=_deprecation_warning_channels("channel2_enabled"),
+        preprocess_reply=_deprecation_warning_channels("channel2_enabled"),
     )
 
     power = Instrument.control(


Test patch:
diff --git a/tests/instruments/toptica/test_ibeamsmart.py b/tests/instruments/toptica/test_ibeamsmart.py
--- a/tests/instruments/toptica/test_ibeamsmart.py
+++ b/tests/instruments/toptica/test_ibeamsmart.py
@@ -90,6 +90,24 @@ def test_enable_channel():
         assert inst.ch_2.enabled is False
 
 
+def test_channel1_enabled_getter():
+    with expected_protocol(
+            IBeamSmart,
+            init_comm + [("sta ch 1", ""), (None, "ON"), (None, "[OK]")],
+    ) as inst:
+        with pytest.warns(FutureWarning):
+            assert inst.channel1_enabled is True
+
+
+def test_channel1_enabled_setter():
+    with expected_protocol(
+            IBeamSmart,
+            init_comm + [("en 1", ""), (None, "[OK]")],
+    ) as inst:
+        with pytest.warns(FutureWarning):
+            inst.channel1_enabled = True
+
+
 def test_channel_power():
     with expected_protocol(
             IBeamSmart,