예제 #1
0
    def __init__(self,
                 command: CommandInterface = None,
                 *,
                 current_node: GraphType = None) -> None:
        """A client that resolves calls through the command object interface

        Exposes a similar API to the command graph, but performs resolution of
        objects.  Any navigation done on the command graph is resolved at the
        point it is invoked.  This command resolution is done via the command
        interface.

        Parameters
        ----------
        command: CommandInterface
            The object that is used to resolve command graph calls, as well as
            navigate the command graph.
        current_node: CommandGraphNode
            The current node that is pointed to in the command graph.  If not
            specified, the command graph root is used.
        """
        if command is None:
            command = IPCCommandInterface(Client(find_sockfile()))
        self._command = command
        if current_node is None:
            self._current_node = CommandGraphRoot()  # type: GraphType
        else:
            self._current_node = current_node
예제 #2
0
    def __init__(self,
                 command: CommandInterface = None,
                 *,
                 current_node: GraphType = None) -> None:
        """An interactive client that resolves calls through the gives client

        Exposes the command graph API in such a way that it can be traversed
        directly on this object.  The command resolution for this object is
        done via the command interface.

        Parameters
        ----------
        command: CommandInterface
            The object that is used to resolve command graph calls, as well as
            navigate the command graph.
        current_node: CommandGraphNode
            The current node that is pointed to in the command graph.  If not
            specified, the command graph root is used.
        """
        if command is None:
            command = IPCCommandInterface(Client(find_sockfile()))
        self._command = command
        if current_node is None:
            self._current_node = CommandGraphRoot()  # type: GraphType
        else:
            self._current_node = current_node
예제 #3
0
def test_resolve_selections():
    root_node = CommandGraphRoot()

    node_1 = root_node.navigate("layout", None) \
                      .navigate("screen", "1")
    assert node_1.selectors == [("layout", None), ("screen", "1")]
    assert isinstance(node_1, CommandGraphObject)
예제 #4
0
def test_resolve_command():
    root_node = CommandGraphRoot()

    command_1 = root_node.call("cmd_name")
    assert command_1.selectors == []
    assert command_1.name == "cmd_name"
    assert isinstance(command_1, CommandGraphCall)

    command_2 = root_node.navigate("layout",
                                   None).navigate("screen",
                                                  None).call("cmd_name")
    assert command_2.name == "cmd_name"
    assert command_2.selectors == [("layout", None), ("screen", None)]
    assert isinstance(command_2, CommandGraphCall)
예제 #5
0
def test_resolve_nodes():
    root_node = CommandGraphRoot()

    node_1 = root_node.navigate("layout", None) \
                      .navigate("screen", None)
    assert node_1.selectors == [("layout", None), ("screen", None)]
    assert isinstance(node_1, CommandGraphObject)

    node_2 = node_1.navigate("layout", None) \
                   .navigate("window", None) \
                   .navigate("group", None)
    assert node_2.selectors == [
        ("layout", None), ("screen", None), ("layout", None), ("window", None), ("group", None)
    ]
    assert isinstance(node_2, CommandGraphObject)

    with pytest.raises(KeyError, match="Given node is not an object"):
        node_1.navigate("widget", None)
예제 #6
0
def test_root_path():
    node = CommandGraphRoot()
    assert node.selectors == []
    assert node.selector is None
    assert node.parent is None
예제 #7
0
def print_base_objects() -> None:
    """Prints access objects of Client, use cmd for commands."""
    root = CommandGraphRoot()
    actions = ["-o cmd"] + [f"-o {key}" for key in root.children]
    print("Specify an object on which to execute command")
    print("\n".join(actions))
예제 #8
0
class CommandClient:
    """The object that resolves the commands"""
    def __init__(self,
                 command: CommandInterface = None,
                 *,
                 current_node: GraphType = None) -> None:
        """A client that resolves calls through the command object interface

        Exposes a similar API to the command graph, but performs resolution of
        objects.  Any navigation done on the command graph is resolved at the
        point it is invoked.  This command resolution is done via the command
        interface.

        Parameters
        ----------
        command: CommandInterface
            The object that is used to resolve command graph calls, as well as
            navigate the command graph.
        current_node: CommandGraphNode
            The current node that is pointed to in the command graph.  If not
            specified, the command graph root is used.
        """
        if command is None:
            command = IPCCommandInterface(Client(find_sockfile()))
        self._command = command
        if current_node is None:
            self._current_node = CommandGraphRoot()  # type: GraphType
        else:
            self._current_node = current_node

    def __call__(self, *args, **kwargs) -> Any:
        """When the client has navigated to a command, execute it"""
        if not isinstance(self._current_node, CommandGraphCall):
            raise SelectError("Invalid call", "", self._current_node.selectors)

        return self._command.execute(self._current_node, args, kwargs)

    def navigate(self, name: str, selector: Optional[str]) -> "CommandClient":
        """Resolve the given object in the command graph

        Parameters
        ----------
        name : str
            The name of the command graph object to resolve.
        selector : Optional[str]
            If given, the selector to use to select the next object, and if
            None, then selects the default object.

        Returns
        -------
        CommandClient
            The client with the given command graph object resolved.
        """
        if not isinstance(self._current_node, CommandGraphNode):
            raise SelectError("Invalid navigation", "",
                              self._current_node.selectors)

        if name not in self.children:
            raise SelectError("Not valid child", name,
                              self._current_node.selectors)
        if selector is not None:
            if self._command.has_item(self._current_node, name, selector):
                raise SelectError("Item not available in object", name,
                                  self._current_node.selectors)

        next_node = self._current_node.navigate(name, selector)
        return self.__class__(self._command, current_node=next_node)

    def call(self, name: str) -> "CommandClient":
        """Resolve the call into the command graph

        Parameters
        ----------
        name : str
            The name of the command to resolve in the command graph.

        Returns
        -------
        CommandClient
            The client with the command resolved.
        """
        if not isinstance(self._current_node, CommandGraphNode):
            raise SelectError("Invalid navigation", "",
                              self._current_node.selectors)

        command_call = self._current_node.call("commands")
        commands = self._command.execute(command_call, (), {})
        if name not in commands:
            raise SelectError("Not valid child or command", name,
                              self._current_node.selectors)
        next_node = self._current_node.call(name)
        return self.__class__(self._command, current_node=next_node)

    @property
    def children(self) -> List[str]:
        """Get the children of the current location in the command graph"""
        if isinstance(self._current_node, CommandGraphCall):
            raise SelectError("No children of command graph call", "",
                              self._current_node.selectors)
        return self._current_node.children

    @property
    def root(self) -> "CommandClient":
        """Get the root of the command graph"""
        return self.__class__(self._command)

    @property
    def parent(self) -> "CommandClient":
        """Get the parent of the current client"""
        if self._current_node.parent is None:
            raise SelectError("", "", self._current_node.selectors)
        return self.__class__(self._command,
                              current_node=self._current_node.parent)
예제 #9
0
class InteractiveCommandClient:
    """
    A command graph client that can be used to easily resolve elements interactively
    """
    def __init__(self,
                 command: CommandInterface = None,
                 *,
                 current_node: GraphType = None) -> None:
        """An interactive client that resolves calls through the gives client

        Exposes the command graph API in such a way that it can be traversed
        directly on this object.  The command resolution for this object is
        done via the command interface.

        Parameters
        ----------
        command: CommandInterface
            The object that is used to resolve command graph calls, as well as
            navigate the command graph.
        current_node: CommandGraphNode
            The current node that is pointed to in the command graph.  If not
            specified, the command graph root is used.
        """
        if command is None:
            command = IPCCommandInterface(Client(find_sockfile()))
        self._command = command
        if current_node is None:
            self._current_node = CommandGraphRoot()  # type: GraphType
        else:
            self._current_node = current_node

    def __call__(self, *args, **kwargs) -> Any:
        """When the client has navigated to a command, execute it"""
        if not isinstance(self._current_node, CommandGraphCall):
            raise SelectError("Invalid call", "", self._current_node.selectors)

        return self._command.execute(self._current_node, args, kwargs)

    def __getattr__(self, name: str) -> "InteractiveCommandClient":
        """Get the child element of the currently selected object

        Resolve the element specified by the given name, either the child
        object, or the command on the current object.

        Parameters
        ----------
        name : str
            The name of the element to resolve

        Return
        ------
        InteractiveCommandClient
            The client navigated to the specified name.  Will respresent either
            a command graph node (if the name is a valid child) or a command
            graph call (if the name is a valid command).
        """
        if isinstance(self._current_node, CommandGraphCall):
            raise SelectError("Cannot select children of call", name,
                              self._current_node.selectors)

        # we do not know if the name is a command to be executed, or an object
        # to navigate to
        if name not in self._current_node.children:
            # we are going to resolve a command, check that the command is valid
            if not self._command.has_command(self._current_node, name):
                raise SelectError("Not valid child or command", name,
                                  self._current_node.selectors)
            call_object = self._current_node.call(name)
            return self.__class__(self._command, current_node=call_object)

        next_node = self._current_node.navigate(name, None)
        return self.__class__(self._command, current_node=next_node)

    def __getitem__(self, name: Union[str, int]) -> "InteractiveCommandClient":
        """Get the selected element of the currently selected object

        From the current command graph object, select the instance with the
        given name.

        Parameters
        ----------
        name : str
            The name, or index if it's of int type, of the item to resolve

        Return
        ------
        InteractiveCommandClient
            The current client, navigated to the specified command graph
            object.
        """
        if isinstance(self._current_node, CommandGraphRoot):
            raise KeyError("Root node has no available items", name,
                           self._current_node.selectors)

        if not isinstance(self._current_node, CommandGraphObject):
            raise SelectError("Unable to make selection on current node",
                              str(name), self._current_node.selectors)

        if self._current_node.selector is not None:
            raise SelectError("Selection already made", str(name),
                              self._current_node.selectors)

        # check the selection is valid in the server-side qtile manager
        if not self._command.has_item(self._current_node.parent,
                                      self._current_node.object_type, name):
            raise SelectError("Item not available in object", str(name),
                              self._current_node.selectors)

        next_node = self._current_node.parent.navigate(
            self._current_node.object_type, name)
        return self.__class__(self._command, current_node=next_node)

    def normalize_item(self, item: Union[str, int]) -> Union[str, int]:
        "Normalize the item according to Qtile._items()."
        object_type = self._current_node.object_type \
            if isinstance(self._current_node, CommandGraphObject) else None
        if object_type in ["group", "widget", "bar"]:
            return str(item)
        elif object_type in ["layout", "window", "screen"]:
            return int(item)
        else:
            return item