Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/io/clipboards.py: 93%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

15 statements  

1"""io on the clipboard""" 

2 

3from __future__ import annotations 

4 

5from io import StringIO 

6from typing import TYPE_CHECKING 

7import warnings 

8 

9from pandas._config.config import _global_config as config 

10 

11from pandas._libs import lib 

12from pandas.util._decorators import set_module 

13from pandas.util._exceptions import find_stack_level 

14from pandas.util._validators import check_dtype_backend 

15 

16from pandas.core.dtypes.generic import ABCDataFrame 

17 

18from pandas import option_context 

19 

20if TYPE_CHECKING: 

21 from pandas._typing import DtypeBackend 

22 

23 

24@set_module("pandas") 

25def read_clipboard( 

26 sep: str = r"\s+", 

27 dtype_backend: DtypeBackend | lib.NoDefault = lib.no_default, 

28 **kwargs, 

29): # pragma: no cover 

30 r""" 

31 Read text from clipboard and pass to :func:`~pandas.read_csv`. 

32 

33 Parses clipboard contents similar to how CSV files are parsed 

34 using :func:`~pandas.read_csv`. 

35 

36 Parameters 

37 ---------- 

38 sep : str, default '\\s+' 

39 A string or regex delimiter. The default of ``'\\s+'`` denotes 

40 one or more whitespace characters. 

41 

42 dtype_backend : {'numpy_nullable', 'pyarrow'} 

43 Back-end data type applied to the resultant :class:`DataFrame` 

44 (still experimental). If not specified, the default behavior 

45 is to not use nullable data types. If specified, the behavior 

46 is as follows: 

47 

48 * ``"numpy_nullable"``: returns nullable-dtype-backed :class:`DataFrame` 

49 * ``"pyarrow"``: returns pyarrow-backed nullable 

50 :class:`ArrowDtype` :class:`DataFrame` 

51 

52 .. versionadded:: 2.0 

53 

54 **kwargs 

55 See :func:`~pandas.read_csv` for the full argument list. 

56 

57 Returns 

58 ------- 

59 DataFrame 

60 A parsed :class:`~pandas.DataFrame` object. 

61 

62 See Also 

63 -------- 

64 DataFrame.to_clipboard : Copy object to the system clipboard. 

65 read_csv : Read a comma-separated values (csv) file into DataFrame. 

66 read_fwf : Read a table of fixed-width formatted lines into DataFrame. 

67 

68 Examples 

69 -------- 

70 >>> df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=["A", "B", "C"]) 

71 >>> df.to_clipboard() # doctest: +SKIP 

72 >>> pd.read_clipboard() # doctest: +SKIP 

73 A B C 

74 0 1 2 3 

75 1 4 5 6 

76 """ 

77 encoding = kwargs.pop("encoding", "utf-8") 

78 

79 # only utf-8 is valid for passed value because that's what clipboard 

80 # supports 

81 if encoding is not None and encoding.lower().replace("-", "") != "utf8": 

82 raise NotImplementedError("reading from clipboard only supports utf-8 encoding") 

83 

84 check_dtype_backend(dtype_backend) 

85 

86 from pandas.io.clipboard import clipboard_get 

87 from pandas.io.parsers import read_csv 

88 

89 text = clipboard_get() 

90 

91 # Try to decode (if needed, as "text" might already be a string here). 

92 try: 

93 text = text.decode(kwargs.get("encoding") or config["display"]["encoding"]) 

94 except AttributeError: 

95 pass 

96 

97 # Excel copies into clipboard with \t separation 

98 # inspect no more than the 10 first lines, if they 

99 # all contain an equal number (>0) of tabs, infer 

100 # that this came from excel and set 'sep' accordingly 

101 lines = text[:10000].split("\n")[:-1][:10] # pyright: ignore[reportOptionalSubscript] 

102 

103 # Need to remove leading white space, since read_csv 

104 # accepts: 

105 # a b 

106 # 0 1 2 

107 # 1 3 4 

108 

109 counts = {x.lstrip(" ").count("\t") for x in lines} 

110 if len(lines) > 1 and len(counts) == 1 and counts.pop() != 0: 

111 sep = "\t" 

112 # check the number of leading tabs in the first line 

113 # to account for index columns 

114 index_length = len(lines[0]) - len(lines[0].lstrip(" \t")) 

115 if index_length != 0: 

116 kwargs.setdefault("index_col", list(range(index_length))) 

117 

118 elif not isinstance(sep, str): 

119 raise ValueError(f"{sep=} must be a string") 

120 

121 # Regex separator currently only works with python engine. 

122 # Default to python if separator is multi-character (regex) 

123 if len(sep) > 1 and kwargs.get("engine") is None: 

124 kwargs["engine"] = "python" 

125 elif len(sep) > 1 and kwargs.get("engine") == "c": 

126 warnings.warn( 

127 "read_clipboard with regex separator does not work properly with c engine.", 

128 stacklevel=find_stack_level(), 

129 ) 

130 

131 return read_csv(StringIO(text), sep=sep, dtype_backend=dtype_backend, **kwargs) 

132 

133 

134def to_clipboard( 

135 obj, excel: bool | None = True, sep: str | None = None, **kwargs 

136) -> None: # pragma: no cover 

137 """ 

138 Attempt to write text representation of object to the system clipboard 

139 The clipboard can be then pasted into Excel for example. 

140 

141 Parameters 

142 ---------- 

143 obj : the object to write to the clipboard 

144 excel : bool, defaults to True 

145 if True, use the provided separator, writing in a csv 

146 format for allowing easy pasting into excel. 

147 if False, write a string representation of the object 

148 to the clipboard 

149 sep : optional, defaults to tab 

150 other keywords are passed to to_csv 

151 

152 Notes 

153 ----- 

154 Requirements for your platform 

155 - Linux: xclip, or xsel (with PyQt4 modules) 

156 - Windows: 

157 - OS X: 

158 """ 

159 encoding = kwargs.pop("encoding", "utf-8") 

160 

161 # testing if an invalid encoding is passed to clipboard 

162 if encoding is not None and encoding.lower().replace("-", "") != "utf8": 

163 raise ValueError("clipboard only supports utf-8 encoding") 

164 

165 from pandas.io.clipboard import clipboard_set 

166 

167 if excel is None: 

168 excel = True 

169 

170 if excel: 

171 if sep is None: 

172 sep = "\t" 

173 

174 # Validate sep here rather than catching to_csv's TypeError, which would 

175 # also blame sep for unrelated failures such as a bad keyword (GH#44120) 

176 if isinstance(sep, str) and len(sep) == 1: 

177 buf = StringIO() 

178 

179 # clipboard_set (pyperclip) expects unicode 

180 obj.to_csv(buf, sep=sep, encoding="utf-8", **kwargs) 

181 text = buf.getvalue() 

182 

183 clipboard_set(text) 

184 return 

185 

186 warnings.warn( 

187 "to_clipboard in excel mode requires a single character separator.", 

188 stacklevel=find_stack_level(), 

189 ) 

190 elif sep is not None: 

191 warnings.warn( 

192 "to_clipboard with excel=False ignores the sep argument.", 

193 stacklevel=find_stack_level(), 

194 ) 

195 

196 if isinstance(obj, ABCDataFrame): 

197 # str(df) has various unhelpful defaults, like truncation 

198 with option_context("display.max_colwidth", None): 

199 objstr = obj.to_string(**kwargs) 

200 else: 

201 objstr = str(obj) 

202 clipboard_set(objstr)