microspec.replies¶
Connection to microspeclib¶
Commands receive a low-level response, then instantiate a
high-level response using the classes defined in
replies.
The command populates the high-level response with the attributes of the low-level response. This is the seam where integer codes are replaced with strings and additional attributes are provided as conveniences to applications.
Simple Command Responses¶
Command responses are auto-generated classes defined in
microspeclib. These responses are too low-level for direct
use in applications:
- the command response includes serial communication attributes that applications do not need to access
- all attribute values are integers
- requires users to look up the meaning of the integer
Module replies defines high-level versions of
each command response. This creates a seam to:
hide the serial communication attributes from the application
add attributes as conveniences for applications:
- getExposure returns with attributes for milliseconds and cycles
- captureFrame returns with a dict attribute that packages the pixel data with its pixel number
replace integer values with strings matching the names of the constants defined in
constantsadd a
__repr__to eliminate the need to wrap responses in aprint()when working at the REPL- the
__repr__comes for free with namedtuples (it’s thecollections.namedtuple.__repr__())
- the
add custom docstrings for each response
For developers working on replies¶
For every command defined in microspec.Devkit, there is a
namedtuple in replies with the same name. There is no
name conflict because the commands are methods of Devkit and
the replies are members of the replies module.
For example, microspec.Devkit.getBridgeLED() is a command
which has the response microspec.replies.getBridgeLED.
It is important that the name of a namedtuple is the same as its type name. This has to do with how the Sphinx autodoc extension handles namedtuples.
The preferred (and usual) approach with autodoc is to use the
:members: option and recursively document everything in the
module. But this generates an alias in the documentation.
The alias is generated for:
- the class if the names are different
- the class attributes if the names are the same
Either way, some alias is generated and it shows up as noise
in the documentation.
The alternative to using the :members: option is to
explicitly invoke the autoclass:: directive for the module’s
classes.
When using the autodoc directive autoclass::, if the names of
the namedtuple and its type are different, Sphinx generates an
alias for the class created by the namedtuple.
My solution, therefore, to autodoc a module containing namedtuples is to:
use the same name for the namedtuple and its type name
list each namedtuple with the
autoclass::directivedo not use option
:members:with theautomodule::andautoclass::directives- the
automodule::directive picks up the module docstring without picking up anything else in the module - the
autoclass::directive picks up the namedtuple docstring without picking up class members - the documentation looks like class members were picked up because they are documented in the namedtuple docstring (just as you would do for a class that was not generated by a namedtuple)
- the
Docstrings use text substitution¶
Module replies uses a dictionary to define
snippets of reusable documentation and a shorthand name for each
snippet. These docstring snippets are a single source of truth
for information that is repeated.
How the substitution works¶
The docstrings in module replies use dictionary
_common for reusable docstring snippets.
Here is a simplified example to demonstrate docstring substitution:
>>> _common = {"status": "STATUS", "notes": "NOTES"}
>>> replace_me = '''Docstring with {status} and {notes}.'''
>>> replace_me.format(**_common)
'Docstring with STATUS and NOTES.'
How to handle newlines¶
Trailing \ at the end of a line eliminates the newline
introduced by the multiline string:
>>> one_line = '''This is \
... one line'''
>>> print(one_line)
This is one line
Otherwise the multiline string includes all newlines:
>>> two_lines = '''This is
... two lines'''
>>> print(two_lines)
This is
two lines
Newlines are included even when they are the only character:
>>> three_lines = '''This is
... three lines
... '''
>>> print(three_lines)
This is
three lines