-
Notifications
You must be signed in to change notification settings - Fork 86
API design guidelines
Marcos edited this page Jun 13, 2022
·
12 revisions
- Use Zen of Python as guiding principles
- Follow Python coding conventions
- Use classes to represent each API session
- Expose API properties as properties of Session
- Or of Repeated Capabilities object:
session.channels[0].my_property
- Or of Repeated Capabilities object:
- Use context managers where appropriate:
- Session lifetime
- Acquisition / Generation control
- Session locking (synchronization)
- Use Exceptions for errors
- Use
warnings
package for warnings - Handle memory allocation for the user
- Return values rather than modify references
- Use native Python datatypes as much as possible
- Method names will be derived from C function names
- Enums:
- Names will be derived from CVI FP names (C API has no enums)
- Values will be derived from C constant names
- No support for external calibration
- No support for IVI-specific functions that don't apply to Python (class driver-only, interchangeability stuff, etc.)
- Don't include obsolete functions / properties
- Anything obsoleted after 1.0 release will need to be handled differently
- Anything that's there but can only be used by devices that use "Traditional DAQ" driver
- Don't include functions that are simple wrappers around setting/getting an attribute
- Redundancy means confusion
- Clients don't get type safety benefit that you get in C function anyway
- If there's debate on whether a function should be included or not, then don't include it
- Trivial to add if needed
- Hard to remove once added
- Create "fancy" functions on a case-by-case basis
- Hand-coded Python wrappers replace what would be generated
- Example: niscope.Session.fetch
- Don't use enums as constants
- LabVIEW APIs provide constants as ring controls or enums. Don't do that for Python
- Don't use enums when a
bool
will do- C uses
ViBoolean
but provides named constants. Don't do that for Python - LabVIEW APIs provide ring controls or enums. Don't do that for Python
- We think this is more obvious for Python clients
- If and when a third choice is introduced, we can switch to an enum while maintaining source compatibility thanks to the dynamic nature of Python.
- C uses
- For the most part, defaults are a subset of the defaults in the corresponding LabVIEW VIs
- Less defaults than in LabVIEW APIs, where we may have overdone it
- Defaults can always be added later
- But never removed
- Deviate from LabVIEW default values only in very specific cases (i.e. open session with reset=False)
- Making the method parameters / attributes for terminals simple str, rather than an enum of pre-defined strings.
- For example: `session_to_dev1.digital_edge_measure_trigger_input_terminal = '/Dev2/SourceCompleteEvent'
- This trades off discoverability for power and ease-of-use in large triggering applications.
- In LabVIEW APIs such as NI-DCPower and DAQmx, I/O controls are auto-populated with actual available terminals.
- In LabVIEW APIs such as NI-FGEN and NI-SCOPE, enums obscure this powerful feature.
- In future revisions of our Python APIs, a better solution (programmatically generated docstring and/or enums?) can be devised.
- We went this route (pun intended) because NI's routing subsystem will:
- Find and reserve free routing resources such as PXI trigger lines for you.
- Reuse routing resources when appropriate.
- Program intermediate hardware such as bridges between segments on 18-slot PXI chassis.
- Sadly this doesn't apply to NI-DMM and NI-SWITCH because these drivers have not been updated to support NI's routing subsystem.
- Python lists are slow and inefficient for large data sets
- Use
numpy.array
andarray.array
- "Advanced" API for users who need it or care about it
We acknowledge that we could go further and provide more OOP abstractions similar to .NET APIs. For example, we could provide classes for NI-FGEN's frequency lists, scripts, etc.
We could also have further improved the signatures of some functions had we designed these Python APIs by hand and from scratch.
However, in order to keep things simple, reduce the scope of the project, and make code-generation viable, we have decided against it. Feel free to open an issue if you disagree.