Development Guidelines
I’ve developed this coding guidelines for me over the past year (2024). It
took a long time for me to be happy with code style, and the codebase doesn’t
consistently follow them yet. What’s more, my guidelines are potentially
still in flux; I have changed my mind about style things like Component
variable annotations (forbid => allow) as I write more Amaranth. Bringing
Sentinel up to date with guidelines and/or further refining the below list is a
long term effort.
With that in mind, I’ve found the following coding style guidelines useful for keeping Sentinel managable:
Privacy
Technically, all Components except Top should be treated as “not likely
to change but still private”. However, I don’t think the majority of objects
in the package beginning with underscores looks nice. The compromise I’ve been
using is that “non-nested Components should not begin with underscores”.
Private top-level objects that are not Components are fine.
Actual private classes, objects, functions, etc (begin with an underscore) should have at least a single-line docstring, and more if Ruff complains (e.g. a “Yields” section).
Public API
The Top and FormalTop Signaturess are part of the public interface.
However, Top’s rvfi Signature member is private.
Signatures
Todo
This section of guidelines is still in flux. The source code does not necessarily reflect this section’s guidelines.
Signature objects are not publicly exposed, except maybe the top-level
signature in Top. Bindings for Signature objects are allowed, but
should be private/local to a Component. Despite being private, local
Signature objects should not begin with an underscore if they’re shared
between Python modules (to avoid proliferation of a bunch of attributes
beginning with underscores in public interfaces).
Signature objects are always from the point-of-view of transfer
initiator, even Signature objects without bindings. If a responder
signature is required, generate one using Signature.flip.
Variable Annotations
Components And Data Structures
Component class variable annotations for Signatures should be used when
possible. There is no way to express “always from initiator point-of-view” in
variable annotations. However, variable annotations for Signatures have the
benefit of more compact class __init__ and documentation. I use the following
rules to limit confusion over directions, and it seems to work fine:
In contrast to the previous paragraph, top-level
InandOutFlows forComponentvariable annotations are from the point-of-view of theComponent, even ifComponentis a responder (In) on some of its constituent interfaces.However, if a
Componentcontains nested interface members, their annotations should haveSignaturesfrom the transfer initiator point-of-view, evenSignatureobjects without bindings. If a responderMemberfor a nestedSignatureis required, generate one usingIn.
Note that Parametric Components can’t use class variable annotations; use
an “Attributes” section in the __init__ docstring for these Components.
Likewise, for prefer Struct, Union, etc over StructLayout, UnionLayout,
etc. Their variable annotations make them more compact than Layouts, and they
can still be used anywhere a Layout can.
Class Variables
All class variable annotations (enums, Components, Structs, etc) should
use doc comments
(#:). Try to limit class variables to where they have readily-apparent
benefits (e.g. enums, Component Signatures, Structs, etc).
When useful for cross-referencing (on a best-effort basis), doc comments
for class variables should start with a type (e.g. (#: type: Docs go here)).
This is especially useful for Components, because Sphinx tends to fail to
generate useful links from In(MyType)/Out(MyType) annotations by themselves.
Class Nesting
Mild class nesting is allowed at your own discretion. These can either be
private or public member class variables. If I think functionality will be
useful to others, nested classes/vars are public (e.g. MCause.Cause).
If I think it’s purely an implementation detail that a user shouldn’t access,
the nested class is private (e.g. Insn._CSR was previously private).
Type Annotations
Type annotations are very much a work-in-progress (and likely out-of-date).