Platform Plugins, Defaults, and Real Examples
This page shows how to:
- write a platform plugin (e.g. iOS over Scrapli)
- register defaults to reduce caller verbosity (opt-in)
-
think about capability-driven selection in practice
-
For capabilities and proxy fallbacks: 33-writing-capabilities-and-proxies.md
- For implementing a new library base: 34-writing-base-plugins.md
Example: iOS SSH defaults (Netmiko)
In this repository, iOS ships with a Netmiko SSH plugin registered as both platform and connection-type defaults (default_for_platform=True, default_for_connection_type=True). See neops_worker_sdk/connection/plugins/ios/netmiko_plugin.py.
At call sites you can opt into defaults:
or even:
See 32-method-resolution-priority.md for exactly when defaults apply (and when they don’t).
Example: iOS SSH + DeviceInfoCapability (Scrapli)
This repo also contains a Scrapli-based plugin that implements DeviceInfoCapability:
neops_worker_sdk/connection/plugins/ios/scrapli_plugin.py
It’s a good example of a “real” capability implementation:
- uses
get_raw_connection()to access the underlying Scrapli connection - raises
ConnectionCreationErrorif no connection is available - logs at
infofor a user-visible action andwarningfor parse fallback
Note:
get_raw_connection()returns the underlying library object (e.g. Scrapli driver / Netmiko connection / httpx client).It returns
Noneif the plugin is not connected, the connection was torn down, or the connection is dead.
Capability-driven selection
Consider a proxy that requires DeviceInfoCapability:
from neops_worker_sdk.connection.capabilities import DeviceInfoCapability
from neops_worker_sdk.connection.proxy import ConnectionProxy
class DeviceInfoProxy(ConnectionProxy, DeviceInfoCapability):
pass
If you call without specifying a library:
The resolver considers iOS SSH plugins and filters by capability: only plugins implementing DeviceInfoCapability qualify. This narrows the candidate set and often resolves library ambiguity, but if multiple plugins implement the same capability you may still need to specify the library or opt into defaults.
Writing your own platform plugin
Platform plugins typically:
- inherit the library base plugin (see 34-writing-base-plugins.md)
- inherit one or more capability interfaces
- set
platform = "..."and register with@register_connection_plugin(...)
Skeleton:
from neops_worker_sdk.connection.capabilities import DeviceInfoCapability
from neops_worker_sdk.connection.exceptions import ConnectionCreationError
from neops_worker_sdk.connection.registry import register_connection_plugin
from neops_worker_sdk.connection.plugins.base.scrapli_plugin import ScrapliConnectionPluginBase
@register_connection_plugin(default_for_connection_type=True)
class MyPlatformScrapliPlugin(ScrapliConnectionPluginBase, DeviceInfoCapability):
platform = "my_platform"
def get_version(self) -> dict[str, str | None]:
conn = self.get_raw_connection()
if not conn:
raise ConnectionCreationError(
"No connection available; initialize the connection before calling get_version().",
device_id=str(self.device.id) if self.device.id else None,
)
output = conn.send_command("show version")
return {"vendor": "...", "model": "...", "serial": "...", "software_release": "..."}
Checklist (platform plugin quality)
- Capabilities: implement the capability interface methods you claim to provide
- Exceptions: raise
ConnectionCreationError/ConnectionValidationError(notValueError) - Logging: use
Logger()with appropriate levels (infofor “doing a thing”,warningfor recoverable fallbacks) - Parsing: if parsing fails, return a safe structure with
raw_outputwhen helpful - Defaults: only register defaults when you’re confident they’re safe for most users