Skip to content

Commit ea1a545

Browse files
authored
bpo-46303: Move fileutils.h private functions to internal C API (GH-30484)
Move almost all private functions of Include/cpython/fileutils.h to the internal C API Include/internal/pycore_fileutils.h. Only keep _Py_fopen_obj() in Include/cpython/fileutils.h, since it's used by _testcapi which must not use the internal C API. Move EncodeLocaleEx() and DecodeLocaleEx() functions from _testcapi to _testinternalcapi, since the C API moved to the internal C API.
1 parent fc75bfb commit ea1a545

13 files changed

+289
-258
lines changed

Include/cpython/fileutils.h

Lines changed: 1 addition & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -2,165 +2,7 @@
22
# error "this header file must not be included directly"
33
#endif
44

5-
typedef enum {
6-
_Py_ERROR_UNKNOWN=0,
7-
_Py_ERROR_STRICT,
8-
_Py_ERROR_SURROGATEESCAPE,
9-
_Py_ERROR_REPLACE,
10-
_Py_ERROR_IGNORE,
11-
_Py_ERROR_BACKSLASHREPLACE,
12-
_Py_ERROR_SURROGATEPASS,
13-
_Py_ERROR_XMLCHARREFREPLACE,
14-
_Py_ERROR_OTHER
15-
} _Py_error_handler;
16-
17-
PyAPI_FUNC(_Py_error_handler) _Py_GetErrorHandler(const char *errors);
18-
19-
PyAPI_FUNC(int) _Py_DecodeLocaleEx(
20-
const char *arg,
21-
wchar_t **wstr,
22-
size_t *wlen,
23-
const char **reason,
24-
int current_locale,
25-
_Py_error_handler errors);
26-
27-
PyAPI_FUNC(int) _Py_EncodeLocaleEx(
28-
const wchar_t *text,
29-
char **str,
30-
size_t *error_pos,
31-
const char **reason,
32-
int current_locale,
33-
_Py_error_handler errors);
34-
35-
PyAPI_FUNC(char*) _Py_EncodeLocaleRaw(
36-
const wchar_t *text,
37-
size_t *error_pos);
38-
39-
PyAPI_FUNC(PyObject *) _Py_device_encoding(int);
40-
41-
#if defined(MS_WINDOWS) || defined(__APPLE__)
42-
/* On Windows, the count parameter of read() is an int (bpo-9015, bpo-9611).
43-
On macOS 10.13, read() and write() with more than INT_MAX bytes
44-
fail with EINVAL (bpo-24658). */
45-
# define _PY_READ_MAX INT_MAX
46-
# define _PY_WRITE_MAX INT_MAX
47-
#else
48-
/* write() should truncate the input to PY_SSIZE_T_MAX bytes,
49-
but it's safer to do it ourself to have a portable behaviour */
50-
# define _PY_READ_MAX PY_SSIZE_T_MAX
51-
# define _PY_WRITE_MAX PY_SSIZE_T_MAX
52-
#endif
53-
54-
#ifdef MS_WINDOWS
55-
struct _Py_stat_struct {
56-
unsigned long st_dev;
57-
uint64_t st_ino;
58-
unsigned short st_mode;
59-
int st_nlink;
60-
int st_uid;
61-
int st_gid;
62-
unsigned long st_rdev;
63-
__int64 st_size;
64-
time_t st_atime;
65-
int st_atime_nsec;
66-
time_t st_mtime;
67-
int st_mtime_nsec;
68-
time_t st_ctime;
69-
int st_ctime_nsec;
70-
unsigned long st_file_attributes;
71-
unsigned long st_reparse_tag;
72-
};
73-
#else
74-
# define _Py_stat_struct stat
75-
#endif
76-
77-
PyAPI_FUNC(int) _Py_fstat(
78-
int fd,
79-
struct _Py_stat_struct *status);
80-
81-
PyAPI_FUNC(int) _Py_fstat_noraise(
82-
int fd,
83-
struct _Py_stat_struct *status);
84-
85-
PyAPI_FUNC(int) _Py_stat(
86-
PyObject *path,
87-
struct stat *status);
88-
89-
PyAPI_FUNC(int) _Py_open(
90-
const char *pathname,
91-
int flags);
92-
93-
PyAPI_FUNC(int) _Py_open_noraise(
94-
const char *pathname,
95-
int flags);
96-
97-
PyAPI_FUNC(FILE *) _Py_wfopen(
98-
const wchar_t *path,
99-
const wchar_t *mode);
100-
5+
// Used by _testcapi which must not use the internal C API
1016
PyAPI_FUNC(FILE*) _Py_fopen_obj(
1027
PyObject *path,
1038
const char *mode);
104-
105-
PyAPI_FUNC(Py_ssize_t) _Py_read(
106-
int fd,
107-
void *buf,
108-
size_t count);
109-
110-
PyAPI_FUNC(Py_ssize_t) _Py_write(
111-
int fd,
112-
const void *buf,
113-
size_t count);
114-
115-
PyAPI_FUNC(Py_ssize_t) _Py_write_noraise(
116-
int fd,
117-
const void *buf,
118-
size_t count);
119-
120-
#ifdef HAVE_READLINK
121-
PyAPI_FUNC(int) _Py_wreadlink(
122-
const wchar_t *path,
123-
wchar_t *buf,
124-
/* Number of characters of 'buf' buffer
125-
including the trailing NUL character */
126-
size_t buflen);
127-
#endif
128-
129-
#ifdef HAVE_REALPATH
130-
PyAPI_FUNC(wchar_t*) _Py_wrealpath(
131-
const wchar_t *path,
132-
wchar_t *resolved_path,
133-
/* Number of characters of 'resolved_path' buffer
134-
including the trailing NUL character */
135-
size_t resolved_path_len);
136-
#endif
137-
138-
PyAPI_FUNC(wchar_t*) _Py_wgetcwd(
139-
wchar_t *buf,
140-
/* Number of characters of 'buf' buffer
141-
including the trailing NUL character */
142-
size_t buflen);
143-
144-
PyAPI_FUNC(int) _Py_get_inheritable(int fd);
145-
146-
PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable,
147-
int *atomic_flag_works);
148-
149-
PyAPI_FUNC(int) _Py_set_inheritable_async_safe(int fd, int inheritable,
150-
int *atomic_flag_works);
151-
152-
PyAPI_FUNC(int) _Py_dup(int fd);
153-
154-
#ifndef MS_WINDOWS
155-
PyAPI_FUNC(int) _Py_get_blocking(int fd);
156-
157-
PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking);
158-
#else /* MS_WINDOWS */
159-
PyAPI_FUNC(void*) _Py_get_osfhandle_noraise(int fd);
160-
161-
PyAPI_FUNC(void*) _Py_get_osfhandle(int fd);
162-
163-
PyAPI_FUNC(int) _Py_open_osfhandle_noraise(void *handle, int flags);
164-
165-
PyAPI_FUNC(int) _Py_open_osfhandle(void *handle, int flags);
166-
#endif /* MS_WINDOWS */

Include/internal/pycore_fileutils.h

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,165 @@ extern "C" {
1010

1111
#include <locale.h> /* struct lconv */
1212

13+
typedef enum {
14+
_Py_ERROR_UNKNOWN=0,
15+
_Py_ERROR_STRICT,
16+
_Py_ERROR_SURROGATEESCAPE,
17+
_Py_ERROR_REPLACE,
18+
_Py_ERROR_IGNORE,
19+
_Py_ERROR_BACKSLASHREPLACE,
20+
_Py_ERROR_SURROGATEPASS,
21+
_Py_ERROR_XMLCHARREFREPLACE,
22+
_Py_ERROR_OTHER
23+
} _Py_error_handler;
24+
25+
PyAPI_FUNC(_Py_error_handler) _Py_GetErrorHandler(const char *errors);
26+
27+
PyAPI_FUNC(int) _Py_DecodeLocaleEx(
28+
const char *arg,
29+
wchar_t **wstr,
30+
size_t *wlen,
31+
const char **reason,
32+
int current_locale,
33+
_Py_error_handler errors);
34+
35+
PyAPI_FUNC(int) _Py_EncodeLocaleEx(
36+
const wchar_t *text,
37+
char **str,
38+
size_t *error_pos,
39+
const char **reason,
40+
int current_locale,
41+
_Py_error_handler errors);
42+
43+
PyAPI_FUNC(char*) _Py_EncodeLocaleRaw(
44+
const wchar_t *text,
45+
size_t *error_pos);
46+
47+
PyAPI_FUNC(PyObject *) _Py_device_encoding(int);
48+
49+
#if defined(MS_WINDOWS) || defined(__APPLE__)
50+
/* On Windows, the count parameter of read() is an int (bpo-9015, bpo-9611).
51+
On macOS 10.13, read() and write() with more than INT_MAX bytes
52+
fail with EINVAL (bpo-24658). */
53+
# define _PY_READ_MAX INT_MAX
54+
# define _PY_WRITE_MAX INT_MAX
55+
#else
56+
/* write() should truncate the input to PY_SSIZE_T_MAX bytes,
57+
but it's safer to do it ourself to have a portable behaviour */
58+
# define _PY_READ_MAX PY_SSIZE_T_MAX
59+
# define _PY_WRITE_MAX PY_SSIZE_T_MAX
60+
#endif
61+
62+
#ifdef MS_WINDOWS
63+
struct _Py_stat_struct {
64+
unsigned long st_dev;
65+
uint64_t st_ino;
66+
unsigned short st_mode;
67+
int st_nlink;
68+
int st_uid;
69+
int st_gid;
70+
unsigned long st_rdev;
71+
__int64 st_size;
72+
time_t st_atime;
73+
int st_atime_nsec;
74+
time_t st_mtime;
75+
int st_mtime_nsec;
76+
time_t st_ctime;
77+
int st_ctime_nsec;
78+
unsigned long st_file_attributes;
79+
unsigned long st_reparse_tag;
80+
};
81+
#else
82+
# define _Py_stat_struct stat
83+
#endif
84+
85+
PyAPI_FUNC(int) _Py_fstat(
86+
int fd,
87+
struct _Py_stat_struct *status);
88+
89+
PyAPI_FUNC(int) _Py_fstat_noraise(
90+
int fd,
91+
struct _Py_stat_struct *status);
92+
93+
PyAPI_FUNC(int) _Py_stat(
94+
PyObject *path,
95+
struct stat *status);
96+
97+
PyAPI_FUNC(int) _Py_open(
98+
const char *pathname,
99+
int flags);
100+
101+
PyAPI_FUNC(int) _Py_open_noraise(
102+
const char *pathname,
103+
int flags);
104+
105+
PyAPI_FUNC(FILE *) _Py_wfopen(
106+
const wchar_t *path,
107+
const wchar_t *mode);
108+
109+
PyAPI_FUNC(Py_ssize_t) _Py_read(
110+
int fd,
111+
void *buf,
112+
size_t count);
113+
114+
PyAPI_FUNC(Py_ssize_t) _Py_write(
115+
int fd,
116+
const void *buf,
117+
size_t count);
118+
119+
PyAPI_FUNC(Py_ssize_t) _Py_write_noraise(
120+
int fd,
121+
const void *buf,
122+
size_t count);
123+
124+
#ifdef HAVE_READLINK
125+
PyAPI_FUNC(int) _Py_wreadlink(
126+
const wchar_t *path,
127+
wchar_t *buf,
128+
/* Number of characters of 'buf' buffer
129+
including the trailing NUL character */
130+
size_t buflen);
131+
#endif
132+
133+
#ifdef HAVE_REALPATH
134+
PyAPI_FUNC(wchar_t*) _Py_wrealpath(
135+
const wchar_t *path,
136+
wchar_t *resolved_path,
137+
/* Number of characters of 'resolved_path' buffer
138+
including the trailing NUL character */
139+
size_t resolved_path_len);
140+
#endif
141+
142+
PyAPI_FUNC(wchar_t*) _Py_wgetcwd(
143+
wchar_t *buf,
144+
/* Number of characters of 'buf' buffer
145+
including the trailing NUL character */
146+
size_t buflen);
147+
148+
PyAPI_FUNC(int) _Py_get_inheritable(int fd);
149+
150+
PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable,
151+
int *atomic_flag_works);
152+
153+
PyAPI_FUNC(int) _Py_set_inheritable_async_safe(int fd, int inheritable,
154+
int *atomic_flag_works);
155+
156+
PyAPI_FUNC(int) _Py_dup(int fd);
157+
158+
#ifndef MS_WINDOWS
159+
PyAPI_FUNC(int) _Py_get_blocking(int fd);
160+
161+
PyAPI_FUNC(int) _Py_set_blocking(int fd, int blocking);
162+
#else /* MS_WINDOWS */
163+
PyAPI_FUNC(void*) _Py_get_osfhandle_noraise(int fd);
164+
165+
PyAPI_FUNC(void*) _Py_get_osfhandle(int fd);
166+
167+
PyAPI_FUNC(int) _Py_open_osfhandle_noraise(void *handle, int flags);
168+
169+
PyAPI_FUNC(int) _Py_open_osfhandle(void *handle, int flags);
170+
#endif /* MS_WINDOWS */
171+
13172
// This is used after getting NULL back from Py_DecodeLocale().
14173
#define DECODE_LOCALE_ERR(NAME, LEN) \
15174
((LEN) == (size_t)-2) \

Include/internal/pycore_unicodeobject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
#include "pycore_fileutils.h" // _Py_error_handler
12+
1113

1214
/* runtime lifecycle */
1315

Lib/test/test_codecs.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
import _testcapi
1616
except ImportError:
1717
_testcapi = None
18+
try:
19+
import _testinternalcapi
20+
except ImportError:
21+
_testinternalcapi = None
1822

1923
try:
2024
import ctypes
@@ -3345,7 +3349,7 @@ def test_seeking_write(self):
33453349
self.assertEqual(sr.readline(), b'789\n')
33463350

33473351

3348-
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
3352+
@unittest.skipIf(_testinternalcapi is None, 'need _testinternalcapi module')
33493353
class LocaleCodecTest(unittest.TestCase):
33503354
"""
33513355
Test indirectly _Py_DecodeUTF8Ex() and _Py_EncodeUTF8Ex().
@@ -3359,7 +3363,7 @@ class LocaleCodecTest(unittest.TestCase):
33593363
SURROGATES = "\uDC80\uDCFF"
33603364

33613365
def encode(self, text, errors="strict"):
3362-
return _testcapi.EncodeLocaleEx(text, 0, errors)
3366+
return _testinternalcapi.EncodeLocaleEx(text, 0, errors)
33633367

33643368
def check_encode_strings(self, errors):
33653369
for text in self.STRINGS:
@@ -3399,7 +3403,7 @@ def test_encode_unsupported_error_handler(self):
33993403
self.assertEqual(str(cm.exception), 'unsupported error handler')
34003404

34013405
def decode(self, encoded, errors="strict"):
3402-
return _testcapi.DecodeLocaleEx(encoded, 0, errors)
3406+
return _testinternalcapi.DecodeLocaleEx(encoded, 0, errors)
34033407

34043408
def check_decode_strings(self, errors):
34053409
is_utf8 = (self.ENCODING == "utf-8")

0 commit comments

Comments
 (0)