Skip to content

Commit 1eed1b7

Browse files
authored
Merge pull request #1984 from oddbookworm/scrap
deprecated existing scrap API and replaced it with simpler API
2 parents e307f2b + 3ed9246 commit 1eed1b7

File tree

6 files changed

+218
-2
lines changed

6 files changed

+218
-2
lines changed

buildconfig/stubs/pygame/scrap.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ def put(data_type: str, data: ByteString) -> None: ...
99
def contains(data_type: str) -> bool: ...
1010
def lost() -> bool: ...
1111
def set_mode(mode: int) -> None: ...
12+
def put_text(text: str) -> None: ...
13+
def get_text() -> str: ...
14+
def has_text() -> bool: ...

docs/reST/ref/scrap.rst

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@
1111
**EXPERIMENTAL!**: This API may change or disappear in later pygame releases. If
1212
you use this, your code may break with the next pygame release.
1313

14+
The scrap module is for transferring data to/from the clipboard. This allows for
15+
transferring of strings between pygame and other applications. Currently, only strings
16+
are supported with the ``scrap.put_text``, ``scrap.get_text``, and ``scrap.has_text``
17+
functions. All other functions are deprecated as of pygame 2.2.0 and will be removed
18+
in a future release of pygame.
19+
20+
.. note:: ``scrap.put_text``, ``scrap.get_text``, and ``scrap.has_text`` use the same
21+
clipboard as the rest of the current API, but only strings are compatible with the
22+
new API as of right now.
23+
24+
**THE BELOW INFORMATION IS DEPRECATED IN PYGAME 2.2.0 AND WILL BE REMOVED IN THE FUTURE.**
25+
1426
The scrap module is for transferring data to/from the clipboard. This allows
1527
for cutting and pasting data between pygame and other applications. Some basic
1628
data (MIME) types are defined and registered:
@@ -80,6 +92,8 @@ For an example of how the scrap module works refer to the examples page
8092

8193
.. note:: The scrap module requires :func:`pygame.display.set_mode()` be
8294
called before being initialized.
95+
96+
.. deprecated:: 2.2.0
8397

8498
.. ## pygame.scrap.init ##
8599
@@ -95,6 +109,7 @@ For an example of how the scrap module works refer to the examples page
95109
:rtype: bool
96110

97111
.. versionadded:: 1.9.5
112+
.. deprecated:: 2.2.0
98113

99114
.. ## pygame.scrap.get_init ##
100115
@@ -113,6 +128,8 @@ For an example of how the scrap module works refer to the examples page
113128
no data for the given type is available
114129
:rtype: bytes | None
115130

131+
.. deprecated:: 2.2.0
132+
116133
::
117134

118135
text = pygame.scrap.get(pygame.SCRAP_TEXT)
@@ -137,6 +154,8 @@ For an example of how the scrap module works refer to the examples page
137154
is no data in the clipboard an empty list is returned
138155
:rtype: list
139156

157+
.. deprecated:: 2.2.0
158+
140159
::
141160

142161
for t in pygame.scrap.get_types():
@@ -164,6 +183,8 @@ For an example of how the scrap module works refer to the examples page
164183

165184
:raises pygame.error: if unable to put the data into the clipboard
166185

186+
.. deprecated:: 2.2.0
187+
167188
::
168189

169190
with open("example.bmp", "rb") as fp:
@@ -189,6 +210,8 @@ For an example of how the scrap module works refer to the examples page
189210
clipboard, ``False`` otherwise
190211
:rtype: bool
191212

213+
.. deprecated:: 2.2.0
214+
192215
::
193216

194217
if pygame.scrap.contains(pygame.SCRAP_TEXT):
@@ -210,6 +233,8 @@ For an example of how the scrap module works refer to the examples page
210233
application, ``False`` if the pygame application still owns the clipboard
211234
:rtype: bool
212235

236+
.. deprecated:: 2.2.0
237+
213238
::
214239

215240
if pygame.scrap.lost():
@@ -235,6 +260,55 @@ For an example of how the scrap module works refer to the examples page
235260
:raises ValueError: if the ``mode`` parameter is not
236261
``pygame.SCRAP_CLIPBOARD`` or ``pygame.SCRAP_SELECTION``
237262

263+
.. deprecated:: 2.2.0
264+
238265
.. ## pygame.scrap.set_mode ##
239266
240-
.. ## pygame.scrap ##
267+
.. function:: put_text
268+
269+
| :sl:`Places text into the clipboard.`
270+
| :sg:`put_text(text) -> None`
271+
272+
Places the input text into the clipboard. The data should be a string.
273+
This is the same clipboard as the legacy scrap API when using ``SCRAP_TEXT``.
274+
275+
:param string text: String to be placed into the clipboard
276+
:rtype: None
277+
278+
:raises pygame.error: if video mode has not been set_mode
279+
280+
.. note:: ``pygame.display.set_mode()`` should be called before using the ``scrap`` module
281+
282+
.. versionadded:: 2.2.0
283+
284+
.. ## pygame.scrap.put_text
285+
286+
.. function:: get_text
287+
288+
| :sl:`Gets text from the clipboard.`
289+
| :sg:`get_text() -> str`
290+
291+
Gets text from the clipboard and returns it. If the clipboard is empty,
292+
returns an empty string. This is the same clipboard as the legacy scrap
293+
API when using ``SCRAP_TEXT``.
294+
295+
:rtype: str
296+
297+
.. versionadded:: 2.2.0
298+
299+
.. ## pygame.scrap.get_text
300+
301+
.. function:: has_text
302+
303+
| :sl:`Checks if text is in the clipboard.`
304+
| :sg:`has_text() -> bool`
305+
306+
Returns ``True`` if the clipboard has a string, otherwise returns ``False``.
307+
This is the same clipboard as the legacy scrap API when using ``SCRAP_TEXT``.
308+
309+
:rtype: bool
310+
311+
.. versionadded:: 2.2.0
312+
313+
.. ## pygame.scrap.has_text
314+
.. ## pygame.scrap ##

src_c/doc/scrap_doc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@
88
#define DOC_SCRAP_CONTAINS "contains(type) -> bool\nChecks whether data for a given type is available in the clipboard."
99
#define DOC_SCRAP_LOST "lost() -> bool\nIndicates if the clipboard ownership has been lost by the pygame application."
1010
#define DOC_SCRAP_SETMODE "set_mode(mode) -> None\nSets the clipboard access mode."
11+
#define DOC_SCRAP_PUTTEXT "put_text(text) -> None\nPlaces text into the clipboard."
12+
#define DOC_SCRAP_GETTEXT "get_text() -> str\nGets text from the clipboard."
13+
#define DOC_SCRAP_HASTEXT "has_text() -> bool\nChecks if text is in the clipboard."

src_c/scrap.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ _scrap_lost_scrap(PyObject *self, PyObject *args);
6161
static PyObject *
6262
_scrap_set_mode(PyObject *self, PyObject *args);
6363

64+
static PyObject *
65+
_scrap_get_text(PyObject *self, PyObject *args);
66+
static PyObject *
67+
_scrap_put_text(PyObject *self, PyObject *args);
68+
static PyObject *
69+
_scrap_has_text(PyObject *self, PyObject *args);
70+
6471
/* Determine what type of clipboard we are using */
6572
#if !defined(__WIN32__)
6673
#define SDL2_SCRAP
@@ -93,6 +100,11 @@ _scrap_init(PyObject *self, PyObject *args)
93100
{
94101
VIDEO_INIT_CHECK();
95102

103+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
104+
"pygame.scrap.init deprecated since 2.2.0", 1) == -1) {
105+
return NULL;
106+
}
107+
96108
if (!pygame_scrap_initialized()) {
97109
Py_XDECREF(_clipdata);
98110
Py_XDECREF(_selectiondata);
@@ -120,6 +132,12 @@ _scrap_init(PyObject *self, PyObject *args)
120132
static PyObject *
121133
_scrap_get_init(PyObject *self, PyObject *_null)
122134
{
135+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
136+
"pygame.scrap.get_init deprecated since 2.2.0",
137+
1) == -1) {
138+
return NULL;
139+
}
140+
123141
return PyBool_FromLong(pygame_scrap_initialized());
124142
}
125143

@@ -135,6 +153,12 @@ _scrap_get_types(PyObject *self, PyObject *_null)
135153
PyObject *list;
136154
PyObject *tmp;
137155

156+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
157+
"pygame.scrap.get_types deprecated since 2.2.0",
158+
1) == -1) {
159+
return NULL;
160+
}
161+
138162
PYGAME_SCRAP_INIT_CHECK();
139163
if (!pygame_scrap_lost()) {
140164
switch (_currentmode) {
@@ -176,6 +200,12 @@ _scrap_contains(PyObject *self, PyObject *args)
176200
{
177201
char *type = NULL;
178202

203+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
204+
"pygame.scrap.contains deprecated since 2.2.0",
205+
1) == -1) {
206+
return NULL;
207+
}
208+
179209
if (!PyArg_ParseTuple(args, "s", &type))
180210
return NULL;
181211
if (pygame_scrap_contains(type))
@@ -194,6 +224,13 @@ _scrap_get_scrap(PyObject *self, PyObject *args)
194224
char *scrap_type;
195225
size_t count;
196226

227+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
228+
"pygame.scrap.get deprecated since 2.2.0. Consider using"
229+
" pygame.scrap.get_text instead.",
230+
1) == -1) {
231+
return NULL;
232+
}
233+
197234
PYGAME_SCRAP_INIT_CHECK();
198235

199236
if (!PyArg_ParseTuple(args, "s", &scrap_type))
@@ -266,6 +303,13 @@ _scrap_put_scrap(PyObject *self, PyObject *args)
266303
PyObject *tmp;
267304
static const char argfmt[] = "sy#";
268305

306+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
307+
"pygame.scrap.put deprecated since 2.2.0. Consider using"
308+
" pygame.scrap.put_text instead.",
309+
1) == -1) {
310+
return NULL;
311+
}
312+
269313
PYGAME_SCRAP_INIT_CHECK();
270314

271315
if (!PyArg_ParseTuple(args, argfmt, &scrap_type, &scrap, &scraplen)) {
@@ -318,6 +362,13 @@ static PyObject *
318362
_scrap_set_mode(PyObject *self, PyObject *args)
319363
{
320364
PYGAME_SCRAP_INIT_CHECK();
365+
366+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
367+
"pygame.scrap.set_mode deprecated since 2.2.0",
368+
1) == -1) {
369+
return NULL;
370+
}
371+
321372
if (!PyArg_ParseTuple(args, "i", &_currentmode))
322373
return NULL;
323374

@@ -329,6 +380,75 @@ _scrap_set_mode(PyObject *self, PyObject *args)
329380
Py_RETURN_NONE;
330381
}
331382

383+
/**
384+
* @brief Fetches a python string from the SDL clipboard. If
385+
* there is nothing in the clipboard, it will return empty
386+
*
387+
* @return PyObject*
388+
*/
389+
static PyObject *
390+
_scrap_get_text(PyObject *self, PyObject *args)
391+
{
392+
const SDL_bool hasText = SDL_HasClipboardText();
393+
394+
char *text = SDL_GetClipboardText();
395+
396+
// if SDL_GetClipboardText fails, it returns an empty string
397+
// hasText helps determine if an actual error occurred
398+
// vs just an empty string in the clipboard
399+
if (*text == '\0' && hasText == SDL_TRUE) {
400+
SDL_free(text);
401+
PyErr_SetString(pgExc_SDLError, SDL_GetError());
402+
return NULL;
403+
}
404+
405+
PyObject *returnValue = PyUnicode_FromString(text);
406+
SDL_free(text);
407+
408+
return returnValue;
409+
}
410+
411+
/**
412+
* @brief Puts a python string into the SDL clipboard
413+
*
414+
* @param args A python string to be put into the clipboard
415+
*
416+
* @return PyObject*
417+
*/
418+
static PyObject *
419+
_scrap_put_text(PyObject *self, PyObject *args)
420+
{
421+
char *text;
422+
423+
if (!PyArg_ParseTuple(args, "s", &text)) {
424+
return NULL;
425+
}
426+
427+
if (SDL_SetClipboardText(text)) {
428+
return RAISE(pgExc_SDLError, SDL_GetError());
429+
}
430+
431+
Py_RETURN_NONE;
432+
}
433+
434+
/**
435+
* @brief If the SDL clipboard has something in it, will return True.
436+
* Else it returns False.
437+
*
438+
* @return PyObject*
439+
*/
440+
static PyObject *
441+
_scrap_has_text(PyObject *self, PyObject *args)
442+
{
443+
const SDL_bool hasText = SDL_HasClipboardText();
444+
445+
if (hasText) {
446+
Py_RETURN_TRUE;
447+
}
448+
449+
Py_RETURN_FALSE;
450+
}
451+
332452
static PyMethodDef scrap_builtins[] = {
333453
/*
334454
* Only initialise these functions for ones we know about.
@@ -347,6 +467,9 @@ static PyMethodDef scrap_builtins[] = {
347467
{"set_mode", _scrap_set_mode, METH_VARARGS, DOC_SCRAP_SETMODE},
348468

349469
#endif
470+
{"get_text", _scrap_get_text, METH_NOARGS, DOC_SCRAP_GETTEXT},
471+
{"has_text", _scrap_has_text, METH_NOARGS, DOC_SCRAP_HASTEXT},
472+
{"put_text", _scrap_put_text, METH_VARARGS, DOC_SCRAP_PUTTEXT},
350473
{NULL, NULL, 0, NULL}};
351474

352475
MODINIT_DEFINE(scrap)

test/scrap_tags.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__tags__ = ["ignore", "subprocess_ignore"]
1+
# __tags__ = ["ignore", "subprocess_ignore"]
22

33
# TODO: make scrap_test.py work
44
# This test used to work only on linux and windows.

test/scrap_test.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,19 @@ def test_put(self):
115115

116116
self.assertEqual(r, b"buf")
117117

118+
def test_new_put(self):
119+
"""Ensures that text can be placed into the clipboard"""
120+
text = "Welcome to scrap!"
121+
scrap.put_text(text)
122+
self.assertTrue(scrap.has_text())
123+
self.assertEqual(scrap.get_text(), text)
124+
125+
def test_has_text_when_empty(self):
126+
"""Ensures that has_text returns False when clipboard is empty"""
127+
scrap.put_text("")
128+
self.assertFalse(scrap.has_text())
129+
self.assertEqual(scrap.get_text(), "")
130+
118131

119132
class ScrapModuleClipboardNotOwnedTest(unittest.TestCase):
120133
"""Test the scrap module's functionality when the pygame application is

0 commit comments

Comments
 (0)