# Path: librouteros/exceptions.py
# class TrapError(ProtocolError):
#     """
#     Exception raised when !trap is received.
# 
#     :param int category: Optional integer representing category.
#     :param str message: Error message.
#     """
# 
#     def __init__(self, message: str, category: typing.Union[None, int] = None):
#         self.category = category
#         self.message = message
#         super().__init__()
# 
#     def __str__(self) -> str:
#         return str(self.message.replace('\r\n', ','))
# 
#     def __repr__(self) -> str:
#         return f'{self.__class__.__name__}({self})'
# 
# class MultiTrapError(ProtocolError):
#     """
#     Exception raised when multiple !trap words have been received in one response.
# 
#     :param traps: TrapError instances.
#     """
# 
#     def __init__(self, *traps: TrapError):
#         self.traps = traps
#         super().__init__()
# 
#     def __str__(self) -> str:
#         return ', '.join(str(trap) for trap in self.traps)
# 
# Path: librouteros/protocol.py
# def compose_word(key: str, value: typing.Any) -> str:
#     """
#     Create a attribute word from key, value pair.
#     Values are casted to api equivalents.
#     """
#     return f'={key}={cast_to_api(value)}'
# 
# def parse_word(word: str) -> typing.Tuple[str, typing.Any]:
#     """
#     Split given attribute word to key, value pair.
# 
#     Values are casted to python equivalents.
# 
#     :param word: API word.
#     :returns: Key, value pair.
#     """
#     mapping = {'yes': True, 'true': True, 'no': False, 'false': False}
#     _, key, value = word.split('=', 2)
#     try:
#         value = int(value)                # type: ignore
#     except ValueError:
#         value = mapping.get(value, value) # type: ignore
#     return (key, value)
# 
# class ApiProtocol(Encoder, Decoder):
# 
#     def __init__(self, transport: SocketTransport, encoding: str):
#         self.transport = transport
#         self.encoding = encoding
# 
#     @staticmethod
#     def log(direction_string: str, *sentence: str) -> None:
#         for word in sentence:
#             LOGGER.debug(f'{direction_string} {word!r}')
#         LOGGER.debug(f'{direction_string} EOS')
# 
#     def writeSentence(self, cmd: str, *words: str) -> None:
#         """
#         Write encoded sentence.
# 
#         :param cmd: Command word.
#         :param words: Aditional words.
#         """
#         encoded = self.encodeSentence(cmd, *words)
#         self.log('<---', cmd, *words)
#         self.transport.write(encoded)
# 
#     def readSentence(self) -> typing.Tuple[str, typing.Tuple[str, ...]]:
#         """
#         Read every word untill empty word (NULL byte) is received.
# 
#         :return: Reply word, tuple with read words.
#         """
#         sentence = tuple(word for word in iter(self.readWord, ''))
#         self.log('--->', *sentence)
#         reply_word, words = sentence[0], sentence[1:]
#         if reply_word == '!fatal':
#             self.transport.close()
#             raise FatalError(words[0])
#         return reply_word, words
# 
#     def readWord(self) -> str:
#         byte = self.transport.read(1)
#         # Early return check for null byte
#         if byte == b'\x00':
#             return ''
#         to_read = self.determineLength(byte)
#         byte += self.transport.read(to_read)
#         length = self.decodeLength(byte)
#         word = self.transport.read(length)
#         return word.decode(encoding=self.encoding, errors='ignore')
# 
#     def close(self) -> None:
#         self.transport.close()
# 
# Path: librouteros/query.py
# class Key:
# class Query:
#     def __init__(self, name: str):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __lt__(self, other):
#     def __gt__(self, other):
#     def __str__(self) -> str:
#     def In(self, one, *elems):
#     def __init__(self, path, keys: typing.Sequence[Key], api):
#     def where(self, *args: str):
#     def __iter__(self) -> ResponseIter:
# def And(left: QueryGen, right: QueryGen, *rest: QueryGen) -> QueryGen:
# def Or(left: QueryGen, right: QueryGen, *rest: QueryGen) -> QueryGen:
# 
# Path: librouteros/types.py



import typing
from posixpath import join as pjoin
from librouteros.exceptions import TrapError, MultiTrapError
from librouteros.protocol import (
    compose_word,
    parse_word,
    ApiProtocol,
)
from librouteros import query
from librouteros.types import (
    ReplyDict,
    ResponseIter,
    Response,
)

    def __call__(self, cmd: str, **kwargs: typing.Any) -> ResponseIter:
        """
        Call Api with given command.
        Yield each row.

        :param cmd: Command word. eg. /ip/address/print
        :param kwargs: Dictionary with optional arguments.
        """
        words = (compose_word(key, value) for key, value in kwargs.items())
        self.protocol.writeSentence(cmd, *words)
        yield from self.readResponse()

    def rawCmd(self, cmd: str, *words: str) -> ResponseIter:
        """
        Call Api with given command and raw words.
        End user is responsible to properly format each api word argument.
        :param cmd: Command word. eg. /ip/address/print
        :param args: Iterable with optional plain api arguments.
        """
        self.protocol.writeSentence(cmd, *words)
        yield from self.readResponse()

    def readSentence(self) -> typing.Tuple[str, ReplyDict]:
        """
        Read one sentence and parse words.

        :returns: Reply word, dict with attribute words.
        """
        reply_word, words = self.protocol.readSentence()

# Path: librouteros/exceptions.py
# class TrapError(ProtocolError):
#     """
#     Exception raised when !trap is received.
# 
#     :param int category: Optional integer representing category.
#     :param str message: Error message.
#     """
# 
#     def __init__(self, message: str, category: typing.Union[None, int] = None):
#         self.category = category
#         self.message = message
#         super().__init__()
# 
#     def __str__(self) -> str:
#         return str(self.message.replace('\r\n', ','))
# 
#     def __repr__(self) -> str:
#         return f'{self.__class__.__name__}({self})'
# 
# class MultiTrapError(ProtocolError):
#     """
#     Exception raised when multiple !trap words have been received in one response.
# 
#     :param traps: TrapError instances.
#     """
# 
#     def __init__(self, *traps: TrapError):
#         self.traps = traps
#         super().__init__()
# 
#     def __str__(self) -> str:
#         return ', '.join(str(trap) for trap in self.traps)
# 
# Path: librouteros/protocol.py
# def compose_word(key: str, value: typing.Any) -> str:
#     """
#     Create a attribute word from key, value pair.
#     Values are casted to api equivalents.
#     """
#     return f'={key}={cast_to_api(value)}'
# 
# def parse_word(word: str) -> typing.Tuple[str, typing.Any]:
#     """
#     Split given attribute word to key, value pair.
# 
#     Values are casted to python equivalents.
# 
#     :param word: API word.
#     :returns: Key, value pair.
#     """
#     mapping = {'yes': True, 'true': True, 'no': False, 'false': False}
#     _, key, value = word.split('=', 2)
#     try:
#         value = int(value)                # type: ignore
#     except ValueError:
#         value = mapping.get(value, value) # type: ignore
#     return (key, value)
# 
# class ApiProtocol(Encoder, Decoder):
# 
#     def __init__(self, transport: SocketTransport, encoding: str):
#         self.transport = transport
#         self.encoding = encoding
# 
#     @staticmethod
#     def log(direction_string: str, *sentence: str) -> None:
#         for word in sentence:
#             LOGGER.debug(f'{direction_string} {word!r}')
#         LOGGER.debug(f'{direction_string} EOS')
# 
#     def writeSentence(self, cmd: str, *words: str) -> None:
#         """
#         Write encoded sentence.
# 
#         :param cmd: Command word.
#         :param words: Aditional words.
#         """
#         encoded = self.encodeSentence(cmd, *words)
#         self.log('<---', cmd, *words)
#         self.transport.write(encoded)
# 
#     def readSentence(self) -> typing.Tuple[str, typing.Tuple[str, ...]]:
#         """
#         Read every word untill empty word (NULL byte) is received.
# 
#         :return: Reply word, tuple with read words.
#         """
#         sentence = tuple(word for word in iter(self.readWord, ''))
#         self.log('--->', *sentence)
#         reply_word, words = sentence[0], sentence[1:]
#         if reply_word == '!fatal':
#             self.transport.close()
#             raise FatalError(words[0])
#         return reply_word, words
# 
#     def readWord(self) -> str:
#         byte = self.transport.read(1)
#         # Early return check for null byte
#         if byte == b'\x00':
#             return ''
#         to_read = self.determineLength(byte)
#         byte += self.transport.read(to_read)
#         length = self.decodeLength(byte)
#         word = self.transport.read(length)
#         return word.decode(encoding=self.encoding, errors='ignore')
# 
#     def close(self) -> None:
#         self.transport.close()
# 
# Path: librouteros/query.py
# class Key:
# class Query:
#     def __init__(self, name: str):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __lt__(self, other):
#     def __gt__(self, other):
#     def __str__(self) -> str:
#     def In(self, one, *elems):
#     def __init__(self, path, keys: typing.Sequence[Key], api):
#     def where(self, *args: str):
#     def __iter__(self) -> ResponseIter:
# def And(left: QueryGen, right: QueryGen, *rest: QueryGen) -> QueryGen:
# def Or(left: QueryGen, right: QueryGen, *rest: QueryGen) -> QueryGen:
# 
# Path: librouteros/types.py



# Path: librouteros/api.py
import typing
from posixpath import join as pjoin
from librouteros.exceptions import TrapError, MultiTrapError
from librouteros.protocol import (
    compose_word,
    parse_word,
    ApiProtocol,
)
from librouteros import query
from librouteros.types import (
    ReplyDict,
    ResponseIter,
    Response,
)


    def __call__(self, cmd: str, **kwargs: typing.Any) -> ResponseIter:
        """
        Call Api with given command.
        Yield each row.

        :param cmd: Command word. eg. /ip/address/print
        :param kwargs: Dictionary with optional arguments.
        """
        words = (compose_word(key, value) for key, value in kwargs.items())
        self.protocol.writeSentence(cmd, *words)
        yield from self.readResponse()

    def rawCmd(self, cmd: str, *words: str) -> ResponseIter:
        """
        Call Api with given command and raw words.
        End user is responsible to properly format each api word argument.
        :param cmd: Command word. eg. /ip/address/print
        :param args: Iterable with optional plain api arguments.
        """
        self.protocol.writeSentence(cmd, *words)
        yield from self.readResponse()

    def readSentence(self) -> typing.Tuple[str, ReplyDict]:
        """
        Read one sentence and parse words.

        :returns: Reply word, dict with attribute words.
        """
        reply_word, words = self.protocol.readSentence()

        return reply_word, dict(parse_word(word) for word in words)