Hello, world!
Let's start with a basic frontend plugin, Hello, world!
style. This is all
you need:
from dqcsim.plugin import *
@plugin("My Plugin", "Me!", "0.1")
class MyPlugin(Frontend):
def handle_run(self):
self.info('Hello, world!')
MyPlugin().run()
This frontend just logs Hello, world!
with the info loglevel when run. You
can use the command line to test it as follows:
$ dqcsim my-plugin.py null
... Info dqcsim Starting Simulation with seed: ...
... Info back Running null backend initialization callback
... Info dqcsim Executing 'start(...)' host call...
... Info dqcsim Executing 'wait()' host call...
... Info front Hello, world!
... Note dqcsim 'wait()' returned {}
... Info dqcsim Reproduction file written to "my-plugin.py.repro".
... Info dqcsim Simulation completed successfully.
... Info dqcsim PluginProcess exited with status code: 0
... Info dqcsim PluginProcess exited with status code: 0
Note the Hello, world!
line in the middle.
While you're debugging a plugin, you might want to change the log verbosities around a little. For instance, the following will set the verbosity of your plugin to the debug level, and the verbosity of the other plugins and DQCsim itself to error.
$ dqcsim -ld --plugin-level e --dqcsim-level e my-plugin.py -ld null
... Info front Hello, world!
Take a few minutes to look through dqcsim --long-help
to see what those
options mean and what else it can do for you, specifically on the subject of
logging!
How it works
Let's dissect the hello world plugin line by line.
from dqcsim.plugin import *
This loads the DQCsim plugin library and pulls it into our module's scope.
Specifically, we're using Frontend
and plugin
in this script.
@plugin("My Plugin", "Me!", "0.1")
class MyPlugin(Frontend):
These lines define a new plugin. Any plugin must derive from either Frontend
,
Operator
, or Backend
; we're deriving from Frontend
here.
The @plugin
annotation specifies some metadata for the plugin, namely the
plugin's name, author, and version. The host can access this metadata to verify
that it loaded the right plugin. While DQCsim requires you to specify these
three strings, it doesn't actually do anything with it on its own.
def handle_run(self):
This function is called by DQCsim in response to the start()
command from the
host. There are a couple more callbacks that frontend plugins can define, but
this is the most important one. It's also the only one that's required for a
frontend.
self.info('Hello, world!')
This function sends a log message back to DQCsim. You can also use trace
,
debug
, note
, warn
, error
, or fatal
to get a different loglevel. Any
arguments specified in addition to the first are passed to
str.format()
,
so you could for instance also call self.info('Hello, {}!', username)
(if
username
would be a thing here).
MyPlugin().run()
This line actually turns the Python script into a DQCsim plugin. Without it, DQCsim would crash:
Fatal dqcsim plugin did not connect within specified timeout
After all, just defining a class doesn't really make a Python script do anything!
The first part of the line, MyPlugin()
, makes an instance of the plugin, but
doesn't start it yet. This is because there are multiple ways to start a
plugin, and it's also useful to pass instantiated but not-yet-started plugins
around during initialization.
The second part, .run()
, actually starts the plugin. It also waits for it to
finish, and either returns None
to indicate success or throws a
RuntimeError
to indicate failure.
Plugins need a simulator to connect to. DQCsim passes this endpoint as a string
to the first command-line argument of a plugin process. run()
let's you
specify the endpoint manually if you like, but if you don't, it takes it from
sys.argv[1]
automatically, with appropriate error checking.