Qcodes
Qcodes copied to clipboard
A new way of adding parameters that allows overriding inherited parameters (and sphinx auto documentation)
This is a follow up from the discussion in #1151, marked as Draft for now to gather feedback.
Fixes #32 Also sets the infrastructure for fixing #1151
Changes proposed in this pull request:
- Provides a new way of adding parameters to instrument.
- Allows for
Parameters
inheritance with overriding capabilities (#32). - Paves the way for sphinx auto documentation of member parameters (with some hacks, see #1151).
Sphinx result + example, please note the InstanceAttr
in the signature of the added parameters (and source code):
Source code
# Repository: https://gitlab.com/quantify-os/quantify-core
# Licensed according to the LICENCE file on the master branch
"""test feature"""
from qcodes import ManualParameter, Parameter
from qcodes import validators
import qcodes.instrument.base as bs
class MyInstrumentDriver(bs.Instrument):
r"""
MyInstrumentDriver docstring
.. jupyter-execute::
from quantify.utilities.my_mod import MyInstrumentDriver
instr = MyInstrumentDriver(name="instr", special_par=8)
instr.freq(10)
instr.print_readable_snapshot()
print("\ninstr.time.label: ", instr.time.label)
"""
def __init__(self, special_par, *args, **kwargs):
self._call_add_params_from_decorated_methods = False
super().__init__(*args, **kwargs)
self._freq = special_par
self._add_params_from_decorated_methods()
@bs.add_parameter
def _parameter_time( # NB the parameter name will be just `time`
self,
parameter_class=ManualParameter,
initial_value=3,
unit="s",
label="Time",
vals=validators.Numbers(),
):
"""Docstring of :code:`time` parameter"""
@bs.add_parameter
def _parameter_freq( # NB the parameter name will be just `freq`
self,
parameter_class=Parameter,
unit="Hz",
label="Frequency",
vals=validators.Numbers(),
# `self._freq` will be passed to `Parameter`
initial_value=bs.InstanceAttr("_freq"),
# `self._set_freq` will be passed to `Parameter`
set_cmd=bs.InstanceAttr("_set_freq"),
# `self._get_freq` will be passed to `Parameter`
get_cmd=bs.InstanceAttr("_get_freq"),
):
"""Docstring of :code:`freq` parameter"""
def _set_freq(self, value):
self._freq = value
def _get_freq(self):
return self._freq
class SubMyInstrumentDriver(MyInstrumentDriver):
r"""Same as MyInstrumentDriver but overriding a parameter
.. jupyter-execute::
from quantify.utilities.my_mod import SubMyInstrumentDriver
sub_instr = SubMyInstrumentDriver(name="sub_instr", special_par=99)
sub_instr.time(sub_instr.time() * 2)
sub_instr.print_readable_snapshot()
print("\nsub_instr.time.label: ", sub_instr.time.label)
"""
@bs.add_parameter
def _parameter_time( # NB the parameter name will be just `time`
self,
parameter_class=ManualParameter,
initial_value=7,
unit="s",
label="Time long",
vals=validators.Numbers(),
):
"""Docstring of :code:`time` parameter in the subclass"""
To do
- [x] Add tests.
- [x] Document this new way of adding parameters.
- [x] Document how to "hack" Sphinx in order to document these parameters automatically.
- [x] Dealing with the inheritance edge cases, e.g., should we still create the parameter in the parent class and
del
it later and replace it with a new one from the child class?
~~After this MRs one with docs on how to "hack" Sphinx in order to document these parameters automatically.~~
@astafan8 here is a Draft implementation.
@AdriaanRol @JordyGloudemans your feedback is welcome as well.
I have another separate question.
so this feature enables 1) override existing parameters in instrument driver subclasses such that the original parameter won't need even be instantiated, and 2) produce sphinx autodoc documentation for parameters defined in this new way. do you see a lot of widespread use of the capability 1)? i am not so sure about it, because it really depends on how the driver depends on that parameter that one wants to override - for example, if a parameter is used in the init logic of the driver in some way unreplaceable, then overriding may be tricky, and it might be important to keep the original parameter of the parent class so it gets added and used, and the in the subclass one can substitute it with a modified one by doing del self.parameters["param_to_override"]
before self.add_parameter("param_to_override", ...)
.
if you agree with me on this, then the capability 2) in my perspective becomes more widespread, hence i'd suggest to add all code and documentation related to in in this same PR :) what do you think?
@astafan8 thank you very much for quick review, comments have been addressed.
so this feature enables 1) override existing parameters in instrument driver subclasses such that the original parameter won't need even be instantiated, and 2) produce sphinx autodoc documentation for parameters defined in this new way.
do you see a lot of widespread use of the capability 1)?
It was the capability 1) that triggered me to dive into this. Not sure how widespread it will be, but has certainly important applications. The scenario that I believe was most relevant is for virtual instruments that serve as (snapshotable) information container, e.g.,GenericTransmonQubit
that can serve as a overridable template for a SpecialTransmonQubit
.
Perhaps @AdriaanRol can elaborate a bit more on this (next week when he is back from vacation).
i am not so sure about it, because it really depends on how the driver depends on that parameter that one wants to override - for example, if a parameter is used in the init logic of the driver in some way unreplaceable, then overriding may be tricky, and it might be important to keep the original parameter of the parent class so it gets added and used, and the in the subclass one can substitute it with a modified one by doing
del self.parameters["param_to_override"]
beforeself.add_parameter("param_to_override", ...)
.
Fair point, there might some complicated edge cases where this solution is not flexible enough, and perhaps it will never be able to cover every possible case, though it would be nice to be able to use this approach and make sphinx work for all or most scenarios. I am happy to make it more versatile to accommodate for a wide range of use cases, though it would be better to have an exemplary case before building a solution for non-yet-existing problem.
Maybe tagging me in future issues/PRs related to this can help mature this approach as people start using it.
A related potential problem that pops up in my mind is that the order in which parameters are added might matter as well. And if that is the case then the complexity of the inheritance/overriding scheme might grow.
if you agree with me on this, then the capability 2) in my perspective becomes more widespread, hence i'd suggest to add all code and documentation related to in in this same PR :) what do you think?
I am up for this. Changed the description and todo list.
For now I think I will wait to gather some more feedback on the implementation and the issues you raised. The solution for these potential problems is not very clear for now.
perhaps it will never be able to cover every possible case, though it would be nice to be able to use this approach and make sphinx work for all or most scenarios
agree. happy to hear more about the *Qubit
virtual instruments use case and their overriding.
The solution for these potential problems is not very clear for now.
indeed.
I am up for this. Changed the description and todo list.
great! then i'll review after those items are done, ok?
great! then i'll review after those items are done, ok?
Yes, deal! I will tag you when it is ready for a new review :)
@AdriaanRol @JordyGloudemans your feedback is welcome as well.
Thank you for making this ❤️ , you know how much I have been looking forward to this.
I'll try to focus on the "user" side of how this change would affect the writing and readability of instrument drivers as well as the resulting docstrings and how easy they are to understand. I'll try to minimize my comments on the implementation details as the sphinx+decorator magic is a bit of well, magic, to me.
Example instrument "new-style"
I suggest to create a module inside qcodes/instrument_drivers (next to test.py and device.py) with a few example instruments (for example, those from the PR description) that use this new feature. They can also be used later to apply the sphinx hacks and render as part of qcodes docs
Issue #1151 contains a nice example of how an instrument driver looks in the new style. I assume there is probably some subtle differences between the initial design and the current implementation. Could you add an example driver to this MR and maybe also include the sphinx hack so that it is rendered in the docs?
Maybe the best example would be to rewrite the SGS100A microwave source driver using this new style. The reason is that this is the simplest driver, and it would serve as an example on how to write drivers "new-style". However, I see two issues with this. 1. it would delay/block the acceptance of this MR because the new driver needs to be tested, and 2. it enforces a standard before it is tested in working nice. So we should probably postpone the replacing to a later date.
Tweaks to implementation of instrument "new-style"
I'll leave some comments here on the example from #1151.
from qcodes import Instrument, ManualParameter, Parameter
from qcodes import validators
class MyInstrumentDriver(ModifiedInstrumentClass):
"""
MyInstrumentDriver docstring
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._freq = None
@add_parameter
def _parameter_time( # NB the parameter name will be just `time`
self,
parameter_class=ManualParameter,
initial_value=3,
unit="s",
label="Time",
vals=validators.Numbers(),
):
"""Docstring of :code:`time` parameter"""
suggestion, the @add_parameter decorator in combination with the _parameter_
prefix seems double to me. For a user (someone writing a driver) it would be much simpler to directly use the syntax @add_parameter \n def time(....
. For the behind the scenes implementation, this would mean that the time
attribute would be removed and replaced the moment the add_parameter decorator is invoked.
Other than that, I really like the syntax.
I've also left a comment in the add_parameter
decorator.
@add_parameter
def _parameter_freq( # NB the parameter name will be just `freq`
self,
parameter_class=Parameter,
unit="Hz",
label="Frequency",
vals=validators.Numbers(),
set_cmd="_set_freq", # `self._set_freq` will be passed to `Parameter`
get_cmd="_get_freq", # `self._get_freq` will be passed to `Parameter`
):
"""Docstring of :code:`freq` parameter"""
def _set_freq(self, value):
self._freq = value
def _get_freq(self):
return self._freq
Good that you included these in the example.
praise in general, I really like this way of writing drivers from a usability perspective. To me it seems very much in line with the original philosophy of QCoDeS of being easy to write and read for physicists (which does require hiding the magic, but that is fine), but I'll leave that to @astafan8 as the official QCoDeS representative in this MR.
Feedback on how docs are rendered
based on the screenshot above.
praiseI think the fact that parameters now show up in the docs is a vast improvement over not being able to document them at all 👍
I have some questions as I am not as familiar with the sphinx magic you had to invoke to get this to work. At first sight, the parameter documentation seems a bit off and hard to read. This is because all is crammed into the call signature, and only the docstring shows.
A big improvement (in my opinion) is that now you don't get the massive docstring of the parameter base class when. This used to bloat the readability of individual parameters for the user.
I had a look at some of our quantify docs (see screenshot) to see how it works for "normal" objects.
Unless it is trivially easy, I suggest you do not implement these things, I'm mostly trying to assess if this would be possible in the future. question would it be possible to have "parameter" appear as an italics prefix similar to the "class method" in the screenshot I showed. question would it be possible to turn the arguments into a list with bold-faced names and then the text after it or is it better to do this using the docstring. suggestion if the second is preferred, let's include that in the example docstring (i.e., what the settable is, a link to the set_cmd and get_cmd, the unit, etc.
Maybe the best example would be to rewrite the SGS100A microwave source driver using this new style. The reason is that this is the simplest driver, and it would serve as an example on how to write drivers "new-style". However, I see two issues with this. 1. it would delay/block the acceptance of this MR because the new driver needs to be tested, and 2. it enforces a standard before it is tested in working nice. So we should probably postpone the replacing to a later date.
agree with @AdriaanRol (especially happy for the point 2) - let's not add a driver of a real instrument in this PR, just stick to a dummy/test kind of driver.
Thank you for the review @AdriaanRol
Will have to process farther some parts of your feedback, here are a few replies.
suggestion, the @add_parameter decorator in combination with the
_parameter_
prefix seems double to me. For a user (someone writing a driver) it would be much simpler to directly use the syntax@add_parameter \n def time(....
. For the behind the scenes implementation, this would mean that thetime
attribute would be removed and replaced the moment the add_parameter decorator is invoked.
definitely agree, it is a technical limitation in python, if a method def time(...)
is added to the class it cannot be removed... Can't recall anymore if this directly clashes with instrument.time()
or not, but the point is that it better stay away from such ambiguity (meaning, is instrument.time
the old dummy method or the added parameter?). To solves this I made the parameter a private method. To farther avoid clashes with the user's private methods, I introduced the _parameter_
prefix. Not ideal, so the @add_parameter
decorator will educate driver writers about this mandatory prefix 😉.
Feedback on how docs are rendered
I have some questions as I am not as familiar with the sphinx magic you had to invoke to get this to work. At first sight, the parameter documentation seems a bit off and hard to read. This is because all is crammed into the call signature, and only the docstring shows.
Agreed, though will likely keep it out of scope for this Pull Request.
Unless it is trivially easy, I suggest you do not implement these things, I'm mostly trying to assess if this would be possible in the future.
Very likely, sphinx magic and hacking can go pretty far, doing it the "intended" way might be harder.
question would it be possible to have "parameter" appear as an italics prefix similar to the "class method" in the screenshot I showed.
Should be.
question would it be possible to turn the arguments into a list with bold-faced names and then the text after it or is it better to do this using the docstring.
Should be possible to automate this, and I think should be automated, a heads up for making it compatible with both numpy and google style docstring.
suggestion if the second is preferred, let's include that in the example docstring (i.e., what the settable is, a link to the set_cmd and get_cmd, the unit, etc.
User will have this freedom anyway, but the idea would be to automate as much as possible.
Note for self
Some Inspiration:
from sphinx.ext import autodoc
autodoc.PropertyDocumenter??
Init signature:
autodoc.PropertyDocumenter(
directive: 'DocumenterBridge',
name: str,
indent: str = '',
) -> None
Source:
class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore
"""
Specialized Documenter subclass for properties.
"""
objtype = 'property'
directivetype = 'method'
member_order = 60
# before AttributeDocumenter
priority = AttributeDocumenter.priority + 1
@classmethod
def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
) -> bool:
return inspect.isproperty(member) and isinstance(parent, ClassDocumenter)
def document_members(self, all_members: bool = False) -> None:
pass
def get_real_modname(self) -> str:
return self.get_attr(self.parent or self.object, '__module__', None) \
or self.modname
def add_directive_header(self, sig: str) -> None:
super().add_directive_header(sig)
sourcename = self.get_sourcename()
if inspect.isabstractmethod(self.object):
self.add_line(' :abstractmethod:', sourcename)
self.add_line(' :property:', sourcename)
File: /usr/local/anaconda3/envs/q38/lib/python3.8/site-packages/sphinx/ext/autodoc/__init__.py
Type: type
Subclasses:
Note the self.add_line(' :property:', sourcename)
, will be necessary to define a custom :parameter:
role (or directive or several things that i do not know how to refer to correctly) in sphinx as well, likely with added benefit of being able to link to specific parameters throughout the docs.
Internally the Documenter seems to create something like:
.. py:method:: MyInstrumentDriver.bla
:module: quantify.utilities.my_mod
:property:
My docstring over here
Above :property:
is an "option" of the in "py:method" directive.
A "role" in sphinx can be added with
def parameter_role(name, rawtext, text, lineno ,inliner):
# ... ???
# Somehow make it an alias of the default `:meth:` role
def setup(app):
app.add_role("parameter", parameter_role)
A custom documenter as part of qcodes sphinx extension might be the proper way of doing this.
Latest prototype, everything auto-generated:
Sphinx hacks are more elegant than I was imagining.
conf.py source code
from sphinx.ext import autodoc
from sphinx.domains import python as sdp
QCODES_ADD_PARAMETER_FLAG = "_add_parameter"
QCODES_METHOD_PREFIX = "_parameter_"
def format_name(self) -> str:
if hasattr(self.object, QCODES_ADD_PARAMETER_FLAG):
return ".".join(
self.objpath[:-1] + [self.objpath[-1][len(QCODES_METHOD_PREFIX) :]]
)
return ".".join(self.objpath) or self.modname
original_add_directive_header = autodoc.MethodDocumenter.add_directive_header
def add_directive_header(self, sig: str) -> None:
original_add_directive_header(self, sig)
if self.object_name.startswith("_parameter_"):
sourcename = self.get_sourcename()
self.add_line(" :parameter:", sourcename)
original_get_signature_prefix = sdp.PyMethod.get_signature_prefix
def get_signature_prefix(self, sig: str) -> str:
prefix_str = original_get_signature_prefix(self, sig)
if "parameter" in self.options:
prefix_str += "parameter "
return prefix_str
def dont_skip_qcodes_params(app, what, name, obj, skip, options) -> bool:
if hasattr(obj, QCODES_ADD_PARAMETER_FLAG):
return False
return skip
import inspect
def add_parameter_spec_to_docstring(app, what, name, obj, options, lines):
# name is e.g. `"my_module._parameter_time"
if QCODES_METHOD_PREFIX in name:
lines += [
"",
".. rubric:: Arguments passed to "
":meth:`~qcodes.instrument.base.InstrumentBase.add_parameter`:",
"",
]
for kw_name, par_obj in inspect.signature(obj).parameters.items():
if kw_name != "self":
if kw_name == "parameter_class":
# create link to the parameter class
mod = par_obj.default.__module__
class_name = par_obj.default.__name__
value = f":class:`~{mod}.{class_name}`"
else:
value = f"*{par_obj.default!r}*"
if kw_name == "vals":
kw_name = ":mod:`vals <qcodes.utils.validators>`"
else:
kw_name = f"**{kw_name}**"
lines.append(f"- {kw_name} = {value}")
lines += [""]
return lines
def clear_parameter_method_signature(
app, what, name, obj, options, signature, return_annotation
):
if QCODES_METHOD_PREFIX in name:
signature = "()"
return (signature, return_annotation)
def setup(app):
# we can't have a method in the class with the same name as the desired
# parameter, therefore we patch the method name displayed in the sphinx docs
# monkey patching `MethodDocumenter`
# e.g. `_parameter_time` -> `_parameter_time` when displayed in the docs
autodoc.MethodDocumenter.format_name = format_name
autodoc.MethodDocumenter.add_directive_header = add_directive_header
sdp.PyMethod.option_spec.update(
{"parameter": sdp.PyMethod.option_spec["classmethod"]}
)
sdp.PyMethod.get_signature_prefix = get_signature_prefix
# enforce documenting the decorated private method
app.connect("autodoc-skip-member", dont_skip_qcodes_params)
app.connect("autodoc-process-docstring", add_parameter_spec_to_docstring)
app.connect("autodoc-process-signature", clear_parameter_method_signature)
Good night! 😝
@astafan8 I have improved the sphinx hacks by creating a sphinx extension and added documentation. Only missing tests. Could you review these parts? I think the code and docs are in a finished or close to finished state.
@caenrigen How this this PR work together with the existing docstring
argument for qcodes Parameters? It is uses by several drivers to provide docstrings to the qcodes Parameters. (Sphinx does not pick them up, as the Parameters are created dynamically, but it does with with spyder and ipython).
@caenrigen will review within the coming days! at a quick glance - looks great, especially the documentation depth and the sphinx extension part :) in the meantime, there's still some work to do for typing https://github.com/QCoDeS/Qcodes/pull/3098/checks?check_run_id=2877069226
@caenrigen will review within the coming days! at a quick glance - looks great, especially the documentation depth and the sphinx extension part :) in the meantime, there's still some work to do for typing https://github.com/QCoDeS/Qcodes/pull/3098/checks?check_run_id=2877069226
Thanks, @astafan8!
Also created this draft for a driver that uses inheritance and can already use the sphinx extension: https://github.com/QCoDeS/Qcodes_contrib_drivers/pull/98
@astafan8 I think I have addressed all comment regarding the docs. Will continue later this week (hopefully) with some tests.
@astafan8 tests added!
It would be nice to have them for the sphinx extension as well, but I have no idea how that is done nor how difficult or time consuming it is to do it properly, sphinx in general is a bit of a magic black box.
Chores:
You need to configure codacy to ignore either D212 or D213 they are mutually excluding otherwise the pipeline will never pass... Could you take care of these warnings according to the standard that you adopt?
Ready to merge? :)
Hey folks! Any progress on this PR? let me know if there is anything required from my side :)
@caenrigen Sorry for waiting. Your work on this feature initiated a thorough alignment among maintainers, and now we are coming back with a suggestion. It started with the observation that while what this PR (the private method approach) enables is very neat, the code one the driver developer side is a bit too complex making the drivers somewhat harder to read. We were looking into options of how to preserve the simple/straightforward syntax of defining parameters and still have the benefit of documenting parameters. So, I tried coming up with a suggestion that makes driver implementation simpler but at the cost of moving the logic to enable the documentation into a sphinx extension that has to rely on parsing the code. I pushed the alternative suggestion into https://github.com/QCoDeS/Qcodes/pull/3188. What do you think of it? (we can discuss the tech details of the proposal in that PR)
Hi! @jenshnielsen Thank you for the updated, was reading the description of #3188 just before your comment.
Your work on this feature initiated a thorough alignment among maintainers, and now we are coming back with a suggestion.
I am glad that you have looked into this more deeply 🙂.
I am taking a few days off and will try to have a look into #3188 somewhere by the end of next week. For now I will leave a few comments.
It started with the observation that while what this PR (the private method approach) enables is very neat, the code one the driver developer side is a bit too complex making the drivers somewhat harder to read.
I agree, it is a bit more complex, it abuses python in a few ways 😅. We found the benefits worth it since no alternative was available, and I put significant effort into documenting how it is intended to be used. Writing a qcodes driver requires reading docs in most cases anyway, I had to do it myself when writing https://github.com/QCoDeS/Qcodes_contrib_drivers/pull/98.
I would suggest to have a look there to confirm that #3188 can provide the same functionalities, I used the @add_paramer
style to implement drivers with inheritance.
In short, I am open to alternatives as long as their simplicity still allows for complex functionality. "Simple things should be simple, complex things should be possible."
So, I tried coming up with a suggestion that makes driver implementation simpler but at the cost of moving the logic to enable the documentation into a sphinx extension that has to rely on parsing the code.
(Disclaimer: I have not look at the implementation) My intuition is that parsing code can be more fragile. Also, I had a hard time creating the sphinx extension, therefore I am not sure if moving a lot of complexity in there is a good idea, since it might be very hard to maintain.
I will try to gather some feedback within Quantify, and play with #3188 when I am back so that I can have an informed opinion on this topic.
One last question: Do you see both approaches possible to co-exist in qcodes? so that developers can choose themselves?
PS thank you for the #3188! From my own experience, I can imagine that takes some significant work.
@caenrigen thanks for your comments
One last question: Do you see both approaches possible to co-exist in qcodes? so that developers can choose themselves?
Technically I don't think there are any reasons why they cannot. I would say that if there are significant advantages from this approach that the other one does not give we can add this one too. Given the work on abstract parameters in #3125 I see that problem as solved without any more work but perhaps I miss something in this pr? That means that both these prs are largely concerned with improving the documentation.
I agree, it is a bit more complex, it abuses python in a few ways 😅. We found the benefits worth it since no alternative was available, and I put significant effort into documenting how it is intended to be used. Writing a qcodes driver requires reading docs in most cases anyway, I had to do it myself when writing QCoDeS/Qcodes_contrib_drivers#98.
This is largely a matter of preferences but I personally tend to prefer idiomatic python style not only for writing code but also for reading (both for humans and for tools). For example if you implement the Weinschell_8320
as in #3188 the example below will enable a few nice features not possible with the current code or this pr (at least as far as I understand this work).
- Here vscode can autocomplete attenuation directly. This does not work with the add_paramter interface since the code has to be evaluated before the attribute is created and the ide has to be start enough to go via the delegate attr interface.
- VScode is also able to infer that attenuation is a parameter and therefore detect the methods on the parameter class and autocomplete these (even get and set that are dynamically generated )
- In the last line mypy can detect that
get
is misspelledbet
since it knows that attenuation is a parameter that does not have an method calledbet
.
(Disclaimer: I have not look at the implementation) My intuition is that parsing code can be more fragile. Also, I had a hard time creating the sphinx extension, therefore I am not sure if moving a lot of complexity in there is a good idea, since it might be very hard to maintain.
I do agree that is not ideal however I see the trade off a bit differently. To me it is more important that the driver code is as clean as possible and the more complex code is unused at runtime. However the parser would indeed need significant work before that part of it can be merged. This is largely a proof of concept.
PS thank you for the #3188! From my own experience, I can imagine that takes some significant work.
I was able to take significant advantage from your work on how to setup a sphinx extension so thanks for that. It saved me a significant amount of time :)
Hi guys!
Due to limitations in my bandwidth I won't be able to have a proper look into #3188 until likely somewhere in August.
Technically I don't think there are any reasons why they cannot.
@jenshnielsen considering that #3188 might take a while to fully develop, and that this PR is ready and in principle not conflicting with #3188, any chance of including it in 0.27.0?
The #3188 is still interesting and I will be glad to help with that later :)
Thanks again for your contribution. I know you have put a lot of time and effort into this thanks to your contribution, the issue was brought to our attention and we were able to think of ways to do it, but unfortunately we have come to the conclusion that this design is too complicated for us to be able to commit to maintaining it unless there is a significant further gain from this method. In addition we are a bit concerned that 3 methods for adding parameters to instruments is too much and will result in confusion among users. The part of #3188 that is concerned with changes to the actual code is very close to landing via #3191 and has basically only been held back due to me wanting to let it bake on master for awhile before releasing. It will therefor target 0.28. Whit that change the existence of parameters can be documented as long as they are documented as any other attribute.
With regards to the parsing of attributes to improve the documentation of them I feel like this is something that we could actually generalise outside QCoDeS. Rather than the code I originally wrote to remove self parameters and instantiate the parameters we can generate a proxy parameter with a repr that contains the full syntax. That will be a lot simpler and easier to reason about and not specific to QCoDeS parameters.
@jenshnielsen thank you for the reply and consideration
but unfortunately we have come to the conclusion that this design is too complicated for us to be able to commit to maintaining it unless there is a significant further gain from this method
fair enough
With regards to the parsing of attributes to improve the documentation of them I feel like this is something that we could actually generalise outside QCoDeS. Rather than the code I originally wrote to remove self parameters and instantiate the parameters we can generate a proxy parameter with a repr that contains the full syntax. That will be a lot simpler and easier to reason about and not specific to QCoDeS parameters.
Looking forward to this, sounds interesting, keep me updated on the developments of this, feel free to tag me in related PRs. (I also joined the QCoDeS Slack, we can chat there as well when needed.)
Cheers