Skip to content

Commit

Permalink
feat: eager input to *not* read input after writing it
Browse files Browse the repository at this point in the history
  • Loading branch information
carlmontanari committed Jan 17, 2024
1 parent e02100d commit ab20115
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 4 deletions.
8 changes: 7 additions & 1 deletion scrapli/channel/async_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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:
Expand Down
8 changes: 7 additions & 1 deletion scrapli/channel/sync_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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:
Expand Down
18 changes: 17 additions & 1 deletion scrapli/driver/generic/async_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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)

Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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,
)

Expand Down
18 changes: 17 additions & 1 deletion scrapli/driver/generic/sync_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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)

Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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,
)

Expand Down
12 changes: 12 additions & 0 deletions scrapli/driver/network/async_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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,
)

Expand All @@ -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:
"""
Expand All @@ -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
Expand All @@ -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,
)

Expand Down
Loading

0 comments on commit ab20115

Please sign in to comment.