diff --git a/scrapli/channel/async_channel.py b/scrapli/channel/async_channel.py index 652e8884..cb63c9c9 100644 --- a/scrapli/channel/async_channel.py +++ b/scrapli/channel/async_channel.py @@ -455,6 +455,7 @@ async def send_input( *, strip_prompt: bool = True, eager: bool = False, + eager_input: bool = False, ) -> Tuple[bytes, bytes]: """ Primary entry point to send data to devices in shell mode; accept input and returns result @@ -465,6 +466,8 @@ async def send_input( eager: eager mode reads and returns the `_read_until_input` value, but does not attempt to read to the prompt pattern -- this should not be used manually! (only used by `send_configs` with the eager flag set) + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! Returns: Tuple[bytes, bytes]: tuple of "raw" output and "processed" (cleaned up/stripped) output @@ -484,7 +487,10 @@ async def send_input( async with self._channel_lock(): self.write(channel_input=channel_input) - _buf_until_input = await self._read_until_input(channel_input=bytes_channel_input) + + if not eager_input: + _buf_until_input = await self._read_until_input(channel_input=bytes_channel_input) + self.send_return() if not eager: diff --git a/scrapli/channel/sync_channel.py b/scrapli/channel/sync_channel.py index 1584114e..e4289eb8 100644 --- a/scrapli/channel/sync_channel.py +++ b/scrapli/channel/sync_channel.py @@ -456,6 +456,7 @@ def send_input( *, strip_prompt: bool = True, eager: bool = False, + eager_input: bool = False, ) -> Tuple[bytes, bytes]: """ Primary entry point to send data to devices in shell mode; accept input and returns result @@ -466,6 +467,8 @@ def send_input( eager: eager mode reads and returns the `_read_until_input` value, but does not attempt to read to the prompt pattern -- this should not be used manually! (only used by `send_configs` with the eager flag set) + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! Returns: Tuple[bytes, bytes]: tuple of "raw" output and "processed" (cleaned up/stripped) output @@ -485,7 +488,10 @@ def send_input( with self._channel_lock(): self.write(channel_input=channel_input) - _buf_until_input = self._read_until_input(channel_input=bytes_channel_input) + + if not eager_input: + _buf_until_input = self._read_until_input(channel_input=bytes_channel_input) + self.send_return() if not eager: diff --git a/scrapli/driver/generic/async_driver.py b/scrapli/driver/generic/async_driver.py index 9c98ea69..3a015ad0 100644 --- a/scrapli/driver/generic/async_driver.py +++ b/scrapli/driver/generic/async_driver.py @@ -101,6 +101,7 @@ async def _send_command( strip_prompt: bool = True, failed_when_contains: Optional[Union[str, List[str]]] = None, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> Response: """ @@ -117,6 +118,8 @@ async def _send_command( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed @@ -141,7 +144,7 @@ async def _send_command( failed_when_contains=failed_when_contains, ) raw_response, processed_response = await self.channel.send_input( - channel_input=command, strip_prompt=strip_prompt, eager=eager + channel_input=command, strip_prompt=strip_prompt, eager=eager, eager_input=eager_input ) return self._post_send_command( raw_response=raw_response, processed_response=processed_response, response=response @@ -153,6 +156,7 @@ async def send_command( *, strip_prompt: bool = True, failed_when_contains: Optional[Union[str, List[str]]] = None, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> Response: """ @@ -162,6 +166,8 @@ async def send_command( command: string to send to device in privilege exec mode strip_prompt: strip prompt or not, defaults to True (yes, strip the prompt) failed_when_contains: string or list of strings indicating failure if found in response + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed @@ -177,6 +183,7 @@ async def send_command( command=command, strip_prompt=strip_prompt, failed_when_contains=failed_when_contains, + eager_input=eager_input, timeout_ops=timeout_ops, ) return response @@ -189,6 +196,7 @@ async def send_commands( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -203,6 +211,8 @@ async def send_commands( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -223,6 +233,7 @@ async def send_commands( failed_when_contains=failed_when_contains, timeout_ops=timeout_ops, eager=eager, + eager_input=eager_input, ) responses.append(response) if stop_on_failed and response.failed is True: @@ -238,6 +249,7 @@ async def send_commands( failed_when_contains=failed_when_contains, timeout_ops=timeout_ops, eager=False, + eager_input=eager_input, ) responses.append(response) @@ -251,6 +263,7 @@ async def send_commands_from_file( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -265,6 +278,8 @@ async def send_commands_from_file( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -285,6 +300,7 @@ async def send_commands_from_file( failed_when_contains=failed_when_contains, stop_on_failed=stop_on_failed, eager=eager, + eager_input=eager_input, timeout_ops=timeout_ops, ) diff --git a/scrapli/driver/generic/sync_driver.py b/scrapli/driver/generic/sync_driver.py index 9b832e13..4adfe2cb 100644 --- a/scrapli/driver/generic/sync_driver.py +++ b/scrapli/driver/generic/sync_driver.py @@ -102,6 +102,7 @@ def _send_command( strip_prompt: bool = True, failed_when_contains: Optional[Union[str, List[str]]] = None, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> Response: """ @@ -118,6 +119,8 @@ def _send_command( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed @@ -142,7 +145,7 @@ def _send_command( failed_when_contains=failed_when_contains, ) raw_response, processed_response = self.channel.send_input( - channel_input=command, strip_prompt=strip_prompt, eager=eager + channel_input=command, strip_prompt=strip_prompt, eager=eager, eager_input=eager_input ) return self._post_send_command( raw_response=raw_response, processed_response=processed_response, response=response @@ -154,6 +157,7 @@ def send_command( *, strip_prompt: bool = True, failed_when_contains: Optional[Union[str, List[str]]] = None, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> Response: """ @@ -163,6 +167,8 @@ def send_command( command: string to send to device in privilege exec mode strip_prompt: strip prompt or not, defaults to True (yes, strip the prompt) failed_when_contains: string or list of strings indicating failure if found in response + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed @@ -178,6 +184,7 @@ def send_command( command=command, strip_prompt=strip_prompt, failed_when_contains=failed_when_contains, + eager_input=eager_input, timeout_ops=timeout_ops, ) return response @@ -190,6 +197,7 @@ def send_commands( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -204,6 +212,8 @@ def send_commands( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -224,6 +234,7 @@ def send_commands( failed_when_contains=failed_when_contains, timeout_ops=timeout_ops, eager=eager, + eager_input=eager_input, ) responses.append(response) if stop_on_failed and response.failed is True: @@ -239,6 +250,7 @@ def send_commands( failed_when_contains=failed_when_contains, timeout_ops=timeout_ops, eager=False, + eager_input=eager_input, ) responses.append(response) @@ -252,6 +264,7 @@ def send_commands_from_file( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -266,6 +279,8 @@ def send_commands_from_file( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -286,6 +301,7 @@ def send_commands_from_file( failed_when_contains=failed_when_contains, stop_on_failed=stop_on_failed, eager=eager, + eager_input=eager_input, timeout_ops=timeout_ops, ) diff --git a/scrapli/driver/network/async_driver.py b/scrapli/driver/network/async_driver.py index 87b7dc18..b23bfd1b 100644 --- a/scrapli/driver/network/async_driver.py +++ b/scrapli/driver/network/async_driver.py @@ -219,6 +219,7 @@ async def send_command( *, strip_prompt: bool = True, failed_when_contains: Optional[Union[str, List[str]]] = None, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> Response: """ @@ -230,6 +231,8 @@ async def send_command( command: string to send to device in privilege exec mode strip_prompt: True/False strip prompt from returned output failed_when_contains: string or list of strings indicating failure if found in response + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed @@ -250,6 +253,7 @@ async def send_command( command=command, strip_prompt=strip_prompt, failed_when_contains=failed_when_contains, + eager_input=eager_input, timeout_ops=timeout_ops, ) self._update_response(response) @@ -264,6 +268,7 @@ async def send_commands( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -280,6 +285,8 @@ async def send_commands( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -303,6 +310,7 @@ async def send_commands( failed_when_contains=failed_when_contains, stop_on_failed=stop_on_failed, eager=eager, + eager_input=eager_input, timeout_ops=timeout_ops, ) @@ -319,6 +327,7 @@ async def send_commands_from_file( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -333,6 +342,8 @@ async def send_commands_from_file( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -356,6 +367,7 @@ async def send_commands_from_file( failed_when_contains=failed_when_contains, stop_on_failed=stop_on_failed, eager=eager, + eager_input=eager_input, timeout_ops=timeout_ops, ) diff --git a/scrapli/driver/network/sync_driver.py b/scrapli/driver/network/sync_driver.py index 47906d9b..a2187ffd 100644 --- a/scrapli/driver/network/sync_driver.py +++ b/scrapli/driver/network/sync_driver.py @@ -219,6 +219,7 @@ def send_command( *, strip_prompt: bool = True, failed_when_contains: Optional[Union[str, List[str]]] = None, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> Response: """ @@ -230,6 +231,8 @@ def send_command( command: string to send to device in privilege exec mode strip_prompt: True/False strip prompt from returned output failed_when_contains: string or list of strings indicating failure if found in response + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed @@ -250,6 +253,7 @@ def send_command( command=command, strip_prompt=strip_prompt, failed_when_contains=failed_when_contains, + eager_input=eager_input, timeout_ops=timeout_ops, ) self._update_response(response) @@ -264,6 +268,7 @@ def send_commands( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -280,6 +285,8 @@ def send_commands( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -303,6 +310,7 @@ def send_commands( failed_when_contains=failed_when_contains, stop_on_failed=stop_on_failed, eager=eager, + eager_input=eager_input, timeout_ops=timeout_ops, ) @@ -319,6 +327,7 @@ def send_commands_from_file( failed_when_contains: Optional[Union[str, List[str]]] = None, stop_on_failed: bool = False, eager: bool = False, + eager_input: bool = False, timeout_ops: Optional[float] = None, ) -> MultiResponse: """ @@ -333,6 +342,8 @@ def send_commands_from_file( eager: if eager is True we do not read until prompt is seen at each command sent to the channel. Do *not* use this unless you know what you are doing as it is possible that it can make scrapli less reliable! + eager_input: when true does *not* try to read our input off the channel -- generally + this should be left alone unless you know what you are doing! timeout_ops: timeout ops value for this operation; only sets the timeout_ops value for the duration of the operation, value is reset to initial value after operation is completed. Note that this is the timeout value PER COMMAND sent, not for the total @@ -356,6 +367,7 @@ def send_commands_from_file( failed_when_contains=failed_when_contains, stop_on_failed=stop_on_failed, eager=eager, + eager_input=eager_input, timeout_ops=timeout_ops, )