Args:
            path (Path):
                If set, then vars from path are copied into the new runtime, and vars are copied back out into path
                at the end

        Note:
            If opts is not None and opts['vars'] is set and path is not None, then values of path vars take precedent

async def storm(self, text, opts=None, user=None, path=None):
        '''
        Args:
            path (Path):
                If set, then vars from path are copied into the new runtime, and vars are copied back out into path
                at the end

        Note:
            If opts is not None and opts['vars'] is set and path is not None, then values of path vars take precedent
        '''
        query = self.snap.core.getStormQuery(text)

        # Merge vars from path into opts.vars
        pathvars = path.vars if path is not None else None
        if opts is None:
            if pathvars is None:
                newopts = None
            else:
                newopts = {'vars': pathvars}
        else:
            vars = opts.get('vars')
            if pathvars is None:
                newopts = opts
            elif vars is None:
                newopts = {**opts, **{'vars': pathvars}}
            else:
                newopts = {**opts, **{'vars': {**vars, **pathvars}}}

        with self.snap.getStormRuntime(opts=newopts, user=user) as runt:
            runt.addInput(self)
            async for item in runt.iterStormQuery(query):
                yield item
            if path:
                path.vars.update(runt.vars)