37
37
import pydoc
38
38
import re
39
39
import sys
40
+ import tempfile
41
+ import typing
40
42
import threading
41
43
from code import (
42
44
InteractiveConsole ,
83
85
CompletionItem ,
84
86
)
85
87
from .clipboard import (
86
- can_clip ,
87
88
get_paste_buffer ,
88
89
write_to_paste_buffer ,
89
90
)
@@ -236,6 +237,7 @@ def __init__(
236
237
shortcuts : Optional [Dict [str , str ]] = None ,
237
238
command_sets : Optional [Iterable [CommandSet ]] = None ,
238
239
auto_load_commands : bool = True ,
240
+ allow_clipboard : bool = True ,
239
241
) -> None :
240
242
"""An easy but powerful framework for writing line-oriented command
241
243
interpreters. Extends Python's cmd package.
@@ -283,6 +285,7 @@ def __init__(
283
285
that are currently loaded by Python and automatically
284
286
instantiate and register all commands. If False, CommandSets
285
287
must be manually installed with `register_command_set`.
288
+ :param allow_clipboard: If False, cmd2 will disable clipboard interactions
286
289
"""
287
290
# Check if py or ipy need to be disabled in this instance
288
291
if not include_py :
@@ -436,8 +439,8 @@ def __init__(
436
439
self .pager = 'less -RXF'
437
440
self .pager_chop = 'less -SRXF'
438
441
439
- # This boolean flag determines whether or not the cmd2 application can interact with the clipboard
440
- self ._can_clip = can_clip
442
+ # This boolean flag stores whether cmd2 will allow clipboard related features
443
+ self .allow_clipboard = allow_clipboard
441
444
442
445
# This determines the value returned by cmdloop() when exiting the application
443
446
self .exit_code = 0
@@ -2734,13 +2737,9 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
2734
2737
sys .stdout = self .stdout = new_stdout
2735
2738
2736
2739
elif statement .output :
2737
- import tempfile
2738
2740
2739
- if (not statement .output_to ) and (not self ._can_clip ):
2740
- raise RedirectionError ("Cannot redirect to paste buffer; missing 'pyperclip' and/or pyperclip dependencies" )
2741
-
2742
- # Redirecting to a file
2743
- elif statement .output_to :
2741
+ if statement .output_to :
2742
+ # redirecting to a file
2744
2743
# statement.output can only contain REDIRECTION_APPEND or REDIRECTION_OUTPUT
2745
2744
mode = 'a' if statement .output == constants .REDIRECTION_APPEND else 'w'
2746
2745
try :
@@ -2752,14 +2751,26 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
2752
2751
redir_saved_state .redirecting = True
2753
2752
sys .stdout = self .stdout = new_stdout
2754
2753
2755
- # Redirecting to a paste buffer
2756
2754
else :
2755
+ # Redirecting to a paste buffer
2756
+ # we are going to direct output to a temporary file, then read it back in and
2757
+ # put it in the paste buffer later
2758
+ if not self .allow_clipboard :
2759
+ raise RedirectionError ("Clipboard access not allowed" )
2760
+
2761
+ # attempt to get the paste buffer, this forces pyperclip to go figure
2762
+ # out if it can actually interact with the paste buffer, and will throw exceptions
2763
+ # if it's not gonna work. That way we throw the exception before we go
2764
+ # run the command and queue up all the output. if this is going to fail,
2765
+ # no point opening up the temporary file
2766
+ current_paste_buffer = get_paste_buffer ()
2767
+ # create a temporary file to store output
2757
2768
new_stdout = cast (TextIO , tempfile .TemporaryFile (mode = "w+" ))
2758
2769
redir_saved_state .redirecting = True
2759
2770
sys .stdout = self .stdout = new_stdout
2760
2771
2761
2772
if statement .output == constants .REDIRECTION_APPEND :
2762
- self .stdout .write (get_paste_buffer () )
2773
+ self .stdout .write (current_paste_buffer )
2763
2774
self .stdout .flush ()
2764
2775
2765
2776
# These are updated regardless of whether the command redirected
@@ -4551,8 +4562,6 @@ def do_history(self, args: argparse.Namespace) -> Optional[bool]:
4551
4562
self .last_result = True
4552
4563
return stop
4553
4564
elif args .edit :
4554
- import tempfile
4555
-
4556
4565
fd , fname = tempfile .mkstemp (suffix = '.txt' , text = True )
4557
4566
fobj : TextIO
4558
4567
with os .fdopen (fd , 'w' ) as fobj :
0 commit comments