Skip to content

Commit 1aa40eb

Browse files
authored
ENH: Improve clipboard (#201)
* ENH: Improve clipboard Synchronize clipboard with upstream pandas * TST: Add a test for clipboard * TST: Make test skippable if not available * CLN: Import from main namespace * ENH: Expand kwargs Expand kwargs Add types for all read_csv args * TST: Add tests for overloads
1 parent 8fb0a9b commit 1aa40eb

File tree

3 files changed

+265
-2
lines changed

3 files changed

+265
-2
lines changed

pandas-stubs/_typing.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,6 @@ MergeHow = Literal["left", "right", "outer", "inner"]
211211
JsonOrient = Literal["split", "records", "index", "columns", "values", "table"]
212212
TimestampConvention = Literal["start", "end", "s", "e"]
213213

214+
CSVEngine = Literal["c", "python", "pyarrow", "python-fwf"]
215+
214216
__all__ = ["npt", "type_t"]

pandas-stubs/io/clipboards.pyi

Lines changed: 223 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,225 @@
1+
import csv
2+
from typing import (
3+
Any,
4+
Callable,
5+
Literal,
6+
Sequence,
7+
overload,
8+
)
9+
10+
import numpy as np
111
from pandas.core.frame import DataFrame
12+
from pandas.core.indexes.base import Index
13+
from pandas.core.series import Series
14+
15+
from pandas._typing import (
16+
CompressionOptions,
17+
CSVEngine,
18+
DtypeArg,
19+
StorageOptions,
20+
npt,
21+
)
22+
23+
from pandas.io.parsers import TextFileReader
224

3-
def read_clipboard(sep: str = ..., **kwargs) -> DataFrame: ...
4-
def to_clipboard(obj, excel: bool = ..., sep=..., **kwargs) -> None: ...
25+
@overload
26+
def read_clipboard(
27+
sep: str | None = ...,
28+
*,
29+
delimiter: str | None = ...,
30+
header: int | Sequence[int] | Literal["infer"] | None = ...,
31+
names: list[str] = ...,
32+
index_col: int | str | Sequence[str | int] | Literal[False] | None = ...,
33+
usecols: list[str]
34+
| Sequence[int]
35+
| Series
36+
| Index
37+
| npt.NDArray
38+
| Callable[[str], bool]
39+
| None = ...,
40+
# squeeze: bool | None = ..., # deprecated: 1.4.0
41+
# prefix: str | None = ..., # deprecated: 1.4.0
42+
mangle_dupe_cols: bool = ..., # deprecated: 1.5.0
43+
dtype: DtypeArg | None = ...,
44+
engine: CSVEngine | None = ...,
45+
converters: dict[int | str, Callable[[str], Any]] = ...,
46+
true_values: list[str] = ...,
47+
false_values: list[str] = ...,
48+
skipinitialspace: bool = ...,
49+
skiprows: int | Sequence[int] | Callable[[int], bool] = ...,
50+
skipfooter: int = ...,
51+
nrows: int | None = ...,
52+
na_values: Sequence[str] | dict[str, Sequence[str]] = ...,
53+
keep_default_na: bool = ...,
54+
na_filter: bool = ...,
55+
verbose: bool = ...,
56+
skip_blank_lines: bool = ...,
57+
parse_dates: bool
58+
| Sequence[int]
59+
| list[str]
60+
| Sequence[Sequence[int]]
61+
| dict[str, Sequence[int]] = ...,
62+
infer_datetime_format: bool = ...,
63+
keep_date_col: bool = ...,
64+
date_parser: Callable = ...,
65+
dayfirst: bool = ...,
66+
cache_dates: bool = ...,
67+
iterator: Literal[True],
68+
chunksize: int | None = ...,
69+
compression: CompressionOptions = ...,
70+
thousands: str | None = ...,
71+
decimal: str = ...,
72+
lineterminator: str | None = ...,
73+
quotechar: str = ...,
74+
quoting: int = ...,
75+
doublequote: bool = ...,
76+
escapechar: str | None = ...,
77+
comment: str | None = ...,
78+
encoding: str | None = ...,
79+
encoding_errors: str | None = ...,
80+
dialect: str | csv.Dialect = ...,
81+
# error_bad_lines: bool | None = ..., # Deprecated: 1.3.0
82+
# warn_bad_lines: bool | None = ..., # Deprecated: 1.3.0
83+
on_bad_lines: Literal["error", "warn", "skip"]
84+
| Callable[[list[str]], list[str] | None] = ...,
85+
delim_whitespace: bool = ...,
86+
low_memory: bool = ...,
87+
memory_map: bool = ...,
88+
float_precision: Literal["high", "legacy", "round_trip"] | None = ...,
89+
storage_options: StorageOptions | None = ...,
90+
) -> TextFileReader: ...
91+
@overload
92+
def read_clipboard(
93+
sep: str | None = ...,
94+
*,
95+
delimiter: str | None = ...,
96+
header: int | Sequence[int] | Literal["infer"] | None = ...,
97+
names: list[str] = ...,
98+
index_col: int | str | Sequence[str | int] | Literal[False] | None = ...,
99+
usecols: list[str]
100+
| Sequence[int]
101+
| Series
102+
| Index
103+
| npt.NDArray
104+
| Callable[[str], bool]
105+
| None = ...,
106+
# squeeze: bool | None = ..., # deprecated: 1.4.0
107+
# prefix: str | None = ..., # deprecated: 1.4.0
108+
mangle_dupe_cols: bool = ..., # deprecated: 1.5.0
109+
dtype: DtypeArg | None = ...,
110+
engine: CSVEngine | None = ...,
111+
converters: dict[int | str, Callable[[str], Any]] = ...,
112+
true_values: list[str] = ...,
113+
false_values: list[str] = ...,
114+
skipinitialspace: bool = ...,
115+
skiprows: int | Sequence[int] | Callable[[int], bool] = ...,
116+
skipfooter: int = ...,
117+
nrows: int | None = ...,
118+
na_values: Sequence[str] | dict[str, Sequence[str]] = ...,
119+
keep_default_na: bool = ...,
120+
na_filter: bool = ...,
121+
verbose: bool = ...,
122+
skip_blank_lines: bool = ...,
123+
parse_dates: bool
124+
| Sequence[int]
125+
| list[str]
126+
| Sequence[Sequence[int]]
127+
| dict[str, Sequence[int]] = ...,
128+
infer_datetime_format: bool = ...,
129+
keep_date_col: bool = ...,
130+
date_parser: Callable = ...,
131+
dayfirst: bool = ...,
132+
cache_dates: bool = ...,
133+
iterator: bool = ...,
134+
chunksize: int,
135+
compression: CompressionOptions = ...,
136+
thousands: str | None = ...,
137+
decimal: str = ...,
138+
lineterminator: str | None = ...,
139+
quotechar: str = ...,
140+
quoting: int = ...,
141+
doublequote: bool = ...,
142+
escapechar: str | None = ...,
143+
comment: str | None = ...,
144+
encoding: str | None = ...,
145+
encoding_errors: str | None = ...,
146+
dialect: str | csv.Dialect = ...,
147+
# error_bad_lines: bool | None = ..., # Deprecated: 1.3.0
148+
# warn_bad_lines: bool | None = ..., # Deprecated: 1.3.0
149+
on_bad_lines: Literal["error", "warn", "skip"]
150+
| Callable[[list[str]], list[str] | None] = ...,
151+
delim_whitespace: bool = ...,
152+
low_memory: bool = ...,
153+
memory_map: bool = ...,
154+
float_precision: Literal["high", "legacy", "round_trip"] | None = ...,
155+
storage_options: StorageOptions | None = ...,
156+
) -> TextFileReader: ...
157+
@overload
158+
def read_clipboard(
159+
sep: str | None = ...,
160+
*,
161+
delimiter: str | None = ...,
162+
header: int | Sequence[int] | Literal["infer"] | None = ...,
163+
names: list[str] = ...,
164+
index_col: int | str | Sequence[str | int] | Literal[False] | None = ...,
165+
usecols: list[str]
166+
| Sequence[int]
167+
| Series
168+
| Index
169+
| npt.NDArray
170+
| Callable[[str], bool]
171+
| None = ...,
172+
# squeeze: bool | None = ..., # deprecated: 1.4.0
173+
# prefix: str | None = ..., # deprecated: 1.4.0
174+
mangle_dupe_cols: bool = ..., # deprecated: 1.5.0
175+
dtype: DtypeArg | None = ...,
176+
engine: CSVEngine | None = ...,
177+
converters: dict[int | str, Callable[[str], Any]] = ...,
178+
true_values: list[str] = ...,
179+
false_values: list[str] = ...,
180+
skipinitialspace: bool = ...,
181+
skiprows: int | Sequence[int] | Callable[[int], bool] = ...,
182+
skipfooter: int = ...,
183+
nrows: int | None = ...,
184+
na_values: Sequence[str] | dict[str, Sequence[str]] = ...,
185+
keep_default_na: bool = ...,
186+
na_filter: bool = ...,
187+
verbose: bool = ...,
188+
skip_blank_lines: bool = ...,
189+
parse_dates: bool
190+
| Sequence[int]
191+
| list[str]
192+
| Sequence[Sequence[int]]
193+
| dict[str, Sequence[int]] = ...,
194+
infer_datetime_format: bool = ...,
195+
keep_date_col: bool = ...,
196+
date_parser: Callable = ...,
197+
dayfirst: bool = ...,
198+
cache_dates: bool = ...,
199+
iterator: Literal[False] = ...,
200+
chunksize: None = ...,
201+
compression: CompressionOptions = ...,
202+
thousands: str | None = ...,
203+
decimal: str = ...,
204+
lineterminator: str | None = ...,
205+
quotechar: str = ...,
206+
quoting: int = ...,
207+
doublequote: bool = ...,
208+
escapechar: str | None = ...,
209+
comment: str | None = ...,
210+
encoding: str | None = ...,
211+
encoding_errors: str | None = ...,
212+
dialect: str | csv.Dialect = ...,
213+
# error_bad_lines: bool | None = ..., # Deprecated: 1.3.0
214+
# warn_bad_lines: bool | None = ..., # Deprecated: 1.3.0
215+
on_bad_lines: Literal["error", "warn", "skip"]
216+
| Callable[[list[str]], list[str] | None] = ...,
217+
delim_whitespace: bool = ...,
218+
low_memory: bool = ...,
219+
memory_map: bool = ...,
220+
float_precision: Literal["high", "legacy", "round_trip"] | None = ...,
221+
storage_options: StorageOptions | None = ...,
222+
) -> DataFrame: ...
223+
def to_clipboard(
224+
obj, excel: bool = ..., sep: str | None = ..., **kwargs: Any
225+
) -> None: ...

tests/test_io.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from pandas import (
2+
DataFrame,
3+
read_clipboard,
4+
)
5+
import pytest
6+
from typing_extensions import assert_type
7+
8+
from tests import check
9+
10+
from pandas.io.clipboard import PyperclipException
11+
from pandas.io.parsers import TextFileReader
12+
13+
DF = DataFrame({"a": [1, 2, 3], "b": [0.0, 0.0, 0.0]})
14+
15+
16+
def test_clipboard():
17+
try:
18+
DF.to_clipboard()
19+
except PyperclipException:
20+
pytest.skip("clipboard not available for testing")
21+
check(assert_type(read_clipboard(), DataFrame), DataFrame)
22+
check(assert_type(read_clipboard(iterator=False), DataFrame), DataFrame)
23+
check(assert_type(read_clipboard(chunksize=None), DataFrame), DataFrame)
24+
25+
26+
def test_clipboard_iterator():
27+
try:
28+
DF.to_clipboard()
29+
except PyperclipException:
30+
pytest.skip("clipboard not available for testing")
31+
check(assert_type(read_clipboard(iterator=True), TextFileReader), TextFileReader)
32+
check(
33+
assert_type(read_clipboard(iterator=True, chunksize=None), TextFileReader),
34+
TextFileReader,
35+
)
36+
check(assert_type(read_clipboard(chunksize=1), TextFileReader), TextFileReader)
37+
check(
38+
assert_type(read_clipboard(iterator=False, chunksize=1), TextFileReader),
39+
TextFileReader,
40+
)

0 commit comments

Comments
 (0)