mirror of
https://github.com/python/cpython.git
synced 2024-11-23 09:54:58 +08:00
Issue #16612: Add "Argument Clinic", a compile-time preprocessor
for C files to generate argument parsing code. (See PEP 436.)
This commit is contained in:
parent
5ceae41083
commit
3182680210
@ -10,6 +10,9 @@ Projected release date: 2013-10-20
|
||||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #16612: Add "Argument Clinic", a compile-time preprocessor for
|
||||
C files to generate argument parsing code. (See PEP 436.)
|
||||
|
||||
- Issue #18810: Shift stat calls in importlib.machinery.FileFinder such that
|
||||
the code is optimistic that if something exists in a directory named exactly
|
||||
like the possible package being searched for that it's in actuality a
|
||||
|
@ -549,68 +549,141 @@ PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
|
||||
|
||||
/* Addch, Addstr, Addnstr */
|
||||
|
||||
/*[clinic]
|
||||
module curses
|
||||
|
||||
class curses.window
|
||||
|
||||
curses.window.addch
|
||||
|
||||
[
|
||||
x: int
|
||||
X-coordinate.
|
||||
y: int
|
||||
Y-coordinate.
|
||||
]
|
||||
|
||||
ch: object
|
||||
Character to add.
|
||||
|
||||
[
|
||||
attr: long
|
||||
Attributes for the character.
|
||||
]
|
||||
/
|
||||
|
||||
Paint character ch at (y, x) with attributes attr.
|
||||
|
||||
Paint character ch at (y, x) with attributes attr,
|
||||
overwriting any character previously painted at that location.
|
||||
By default, the character position and attributes are the
|
||||
current settings for the window object.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(curses_window_addch__doc__,
|
||||
"Paint character ch at (y, x) with attributes attr.\n"
|
||||
"\n"
|
||||
"curses.window.addch([x, y,] ch, [attr])\n"
|
||||
" x\n"
|
||||
" X-coordinate.\n"
|
||||
" y\n"
|
||||
" Y-coordinate.\n"
|
||||
" ch\n"
|
||||
" Character to add.\n"
|
||||
" attr\n"
|
||||
" Attributes for the character.\n"
|
||||
"\n"
|
||||
"Paint character ch at (y, x) with attributes attr,\n"
|
||||
"overwriting any character previously painted at that location.\n"
|
||||
"By default, the character position and attributes are the\n"
|
||||
"current settings for the window object.");
|
||||
|
||||
#define CURSES_WINDOW_ADDCH_METHODDEF \
|
||||
{"addch", (PyCFunction)curses_window_addch, METH_VARARGS, curses_window_addch__doc__},
|
||||
|
||||
static PyObject *
|
||||
PyCursesWindow_AddCh(PyCursesWindowObject *self, PyObject *args)
|
||||
curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr);
|
||||
|
||||
static PyObject *
|
||||
curses_window_addch(PyObject *self, PyObject *args)
|
||||
{
|
||||
int rtn, x, y, use_xy = FALSE;
|
||||
PyObject *chobj;
|
||||
PyObject *return_value = NULL;
|
||||
int group_left_1 = 0;
|
||||
int x;
|
||||
int y;
|
||||
PyObject *ch;
|
||||
int group_right_1 = 0;
|
||||
long attr;
|
||||
|
||||
switch (PyTuple_Size(args)) {
|
||||
case 1:
|
||||
if (!PyArg_ParseTuple(args, "O:addch", &ch))
|
||||
return NULL;
|
||||
break;
|
||||
case 2:
|
||||
if (!PyArg_ParseTuple(args, "Ol:addch", &ch, &attr))
|
||||
return NULL;
|
||||
group_right_1 = 1;
|
||||
break;
|
||||
case 3:
|
||||
if (!PyArg_ParseTuple(args, "iiO:addch", &x, &y, &ch))
|
||||
return NULL;
|
||||
group_left_1 = 1;
|
||||
break;
|
||||
case 4:
|
||||
if (!PyArg_ParseTuple(args, "iiOl:addch", &x, &y, &ch, &attr))
|
||||
return NULL;
|
||||
group_right_1 = 1;
|
||||
group_left_1 = 1;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError, "curses.window.addch requires 1 to 4 arguments");
|
||||
return NULL;
|
||||
}
|
||||
return_value = curses_window_addch_impl(self, group_left_1, x, y, ch, group_right_1, attr);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr)
|
||||
/*[clinic checksum: 98ade780397a48d0be48439763424b3b00c92089]*/
|
||||
{
|
||||
PyCursesWindowObject *cwself = (PyCursesWindowObject *)self;
|
||||
int coordinates_group = group_left_1;
|
||||
int attr_group = group_right_1;
|
||||
int rtn;
|
||||
int type;
|
||||
chtype ch;
|
||||
chtype cch;
|
||||
#ifdef HAVE_NCURSESW
|
||||
cchar_t wch;
|
||||
#endif
|
||||
attr_t attr = A_NORMAL;
|
||||
long lattr;
|
||||
const char *funcname;
|
||||
|
||||
switch (PyTuple_Size(args)) {
|
||||
case 1:
|
||||
if (!PyArg_ParseTuple(args, "O;ch or int", &chobj))
|
||||
return NULL;
|
||||
break;
|
||||
case 2:
|
||||
if (!PyArg_ParseTuple(args, "Ol;ch or int,attr", &chobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
break;
|
||||
case 3:
|
||||
if (!PyArg_ParseTuple(args,"iiO;y,x,ch or int", &y, &x, &chobj))
|
||||
return NULL;
|
||||
use_xy = TRUE;
|
||||
break;
|
||||
case 4:
|
||||
if (!PyArg_ParseTuple(args,"iiOl;y,x,ch or int, attr",
|
||||
&y, &x, &chobj, &lattr))
|
||||
return NULL;
|
||||
attr = lattr;
|
||||
use_xy = TRUE;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError, "addch requires 1 to 4 arguments");
|
||||
return NULL;
|
||||
}
|
||||
if (!attr_group)
|
||||
attr = A_NORMAL;
|
||||
|
||||
#ifdef HAVE_NCURSESW
|
||||
type = PyCurses_ConvertToCchar_t(self, chobj, &ch, &wch);
|
||||
type = PyCurses_ConvertToCchar_t(cwself, ch, &cch, &wch);
|
||||
if (type == 2) {
|
||||
funcname = "add_wch";
|
||||
wch.attr = attr;
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwadd_wch(self->win,y,x, &wch);
|
||||
if (coordinates_group)
|
||||
rtn = mvwadd_wch(cwself->win,y,x, &wch);
|
||||
else {
|
||||
rtn = wadd_wch(self->win, &wch);
|
||||
rtn = wadd_wch(cwself->win, &wch);
|
||||
}
|
||||
}
|
||||
else
|
||||
#else
|
||||
type = PyCurses_ConvertToCchar_t(self, chobj, &ch);
|
||||
type = PyCurses_ConvertToCchar_t(cwself, chobj, &cch);
|
||||
#endif
|
||||
if (type == 1) {
|
||||
funcname = "addch";
|
||||
if (use_xy == TRUE)
|
||||
rtn = mvwaddch(self->win,y,x, ch | attr);
|
||||
if (coordinates_group)
|
||||
rtn = mvwaddch(cwself->win,y,x, cch | attr);
|
||||
else {
|
||||
rtn = waddch(self->win, ch | attr);
|
||||
rtn = waddch(cwself->win, cch | attr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1954,7 +2027,7 @@ PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value)
|
||||
|
||||
|
||||
static PyMethodDef PyCursesWindow_Methods[] = {
|
||||
{"addch", (PyCFunction)PyCursesWindow_AddCh, METH_VARARGS},
|
||||
CURSES_WINDOW_ADDCH_METHODDEF
|
||||
{"addnstr", (PyCFunction)PyCursesWindow_AddNStr, METH_VARARGS},
|
||||
{"addstr", (PyCFunction)PyCursesWindow_AddStr, METH_VARARGS},
|
||||
{"attroff", (PyCFunction)PyCursesWindow_AttrOff, METH_VARARGS},
|
||||
|
@ -4143,31 +4143,73 @@ datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
|
||||
tzinfo);
|
||||
}
|
||||
|
||||
/* Return best possible local time -- this isn't constrained by the
|
||||
* precision of a timestamp.
|
||||
*/
|
||||
/*[clinic]
|
||||
module datetime
|
||||
|
||||
@classmethod
|
||||
datetime.now
|
||||
|
||||
tz: object = None
|
||||
Timezone object.
|
||||
|
||||
Returns new datetime object representing current time local to tz.
|
||||
|
||||
If no tz is specified, uses local timezone.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(datetime_now__doc__,
|
||||
"Returns new datetime object representing current time local to tz.\n"
|
||||
"\n"
|
||||
"datetime.now(tz=None)\n"
|
||||
" tz\n"
|
||||
" Timezone object.\n"
|
||||
"\n"
|
||||
"If no tz is specified, uses local timezone.");
|
||||
|
||||
#define DATETIME_NOW_METHODDEF \
|
||||
{"now", (PyCFunction)datetime_now, METH_VARARGS|METH_KEYWORDS|METH_CLASS, datetime_now__doc__},
|
||||
|
||||
static PyObject *
|
||||
datetime_now(PyObject *cls, PyObject *args, PyObject *kw)
|
||||
datetime_now_impl(PyObject *cls, PyObject *tz);
|
||||
|
||||
static PyObject *
|
||||
datetime_now(PyObject *cls, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static char *_keywords[] = {"tz", NULL};
|
||||
PyObject *tz = Py_None;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
|
||||
"|O:now", _keywords,
|
||||
&tz))
|
||||
goto exit;
|
||||
return_value = datetime_now_impl(cls, tz);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
datetime_now_impl(PyObject *cls, PyObject *tz)
|
||||
/*[clinic checksum: 328b54387f4c2f8cb534997e1bd55f8cb38c4992]*/
|
||||
{
|
||||
PyObject *self;
|
||||
PyObject *tzinfo = Py_None;
|
||||
static char *keywords[] = {"tz", NULL};
|
||||
|
||||
if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:now", keywords,
|
||||
&tzinfo))
|
||||
return NULL;
|
||||
if (check_tzinfo_subclass(tzinfo) < 0)
|
||||
/* Return best possible local time -- this isn't constrained by the
|
||||
* precision of a timestamp.
|
||||
*/
|
||||
if (check_tzinfo_subclass(tz) < 0)
|
||||
return NULL;
|
||||
|
||||
self = datetime_best_possible(cls,
|
||||
tzinfo == Py_None ? localtime : gmtime,
|
||||
tzinfo);
|
||||
if (self != NULL && tzinfo != Py_None) {
|
||||
tz == Py_None ? localtime : gmtime,
|
||||
tz);
|
||||
if (self != NULL && tz != Py_None) {
|
||||
/* Convert UTC to tzinfo's zone. */
|
||||
PyObject *temp = self;
|
||||
_Py_IDENTIFIER(fromutc);
|
||||
|
||||
self = _PyObject_CallMethodId(tzinfo, &PyId_fromutc, "O", self);
|
||||
self = _PyObject_CallMethodId(tz, &PyId_fromutc, "O", self);
|
||||
Py_DECREF(temp);
|
||||
}
|
||||
return self;
|
||||
@ -5001,9 +5043,7 @@ static PyMethodDef datetime_methods[] = {
|
||||
|
||||
/* Class methods: */
|
||||
|
||||
{"now", (PyCFunction)datetime_now,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_CLASS,
|
||||
PyDoc_STR("[tz] -> new datetime with tz's local day and time.")},
|
||||
DATETIME_NOW_METHODDEF
|
||||
|
||||
{"utcnow", (PyCFunction)datetime_utcnow,
|
||||
METH_NOARGS | METH_CLASS,
|
||||
|
@ -44,7 +44,7 @@ static PyTypeObject Dbmtype;
|
||||
static PyObject *DbmError;
|
||||
|
||||
static PyObject *
|
||||
newdbmobject(char *file, int flags, int mode)
|
||||
newdbmobject(const char *file, int flags, int mode)
|
||||
{
|
||||
dbmobject *dp;
|
||||
|
||||
@ -361,16 +361,69 @@ static PyTypeObject Dbmtype = {
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
/*[clinic]
|
||||
module dbm
|
||||
|
||||
dbm.open as dbmopen
|
||||
|
||||
filename: str
|
||||
The filename to open.
|
||||
|
||||
flags: str="r"
|
||||
How to open the file. "r" for reading, "w" for writing, etc.
|
||||
|
||||
mode: int(doc_default="0o666") = 0o666
|
||||
If creating a new file, the mode bits for the new file
|
||||
(e.g. os.O_RDWR).
|
||||
|
||||
/
|
||||
|
||||
Return a database object.
|
||||
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(dbmopen__doc__,
|
||||
"Return a database object.\n"
|
||||
"\n"
|
||||
"dbm.open(filename, flags=\'r\', mode=0o666)\n"
|
||||
" filename\n"
|
||||
" The filename to open.\n"
|
||||
" flags\n"
|
||||
" How to open the file. \"r\" for reading, \"w\" for writing, etc.\n"
|
||||
" mode\n"
|
||||
" If creating a new file, the mode bits for the new file\n"
|
||||
" (e.g. os.O_RDWR).");
|
||||
|
||||
#define DBMOPEN_METHODDEF \
|
||||
{"open", (PyCFunction)dbmopen, METH_VARARGS, dbmopen__doc__},
|
||||
|
||||
static PyObject *
|
||||
dbmopen_impl(PyObject *self, const char *filename, const char *flags, int mode);
|
||||
|
||||
static PyObject *
|
||||
dbmopen(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *name;
|
||||
char *flags = "r";
|
||||
int iflags;
|
||||
int mode = 0666;
|
||||
PyObject *return_value = NULL;
|
||||
const char *filename;
|
||||
const char *flags = "r";
|
||||
int mode = 438;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"s|si:open",
|
||||
&filename, &flags, &mode))
|
||||
goto exit;
|
||||
return_value = dbmopen_impl(self, filename, flags, mode);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dbmopen_impl(PyObject *self, const char *filename, const char *flags, int mode)
|
||||
/*[clinic checksum: 61007c796d38af85c8035afa769fb4bb453429ee]*/
|
||||
{
|
||||
int iflags;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
|
||||
return NULL;
|
||||
if ( strcmp(flags, "r") == 0 )
|
||||
iflags = O_RDONLY;
|
||||
else if ( strcmp(flags, "w") == 0 )
|
||||
@ -386,13 +439,11 @@ dbmopen(PyObject *self, PyObject *args)
|
||||
"arg 2 to open should be 'r', 'w', 'c', or 'n'");
|
||||
return NULL;
|
||||
}
|
||||
return newdbmobject(name, iflags, mode);
|
||||
return newdbmobject(filename, iflags, mode);
|
||||
}
|
||||
|
||||
static PyMethodDef dbmmodule_methods[] = {
|
||||
{ "open", (PyCFunction)dbmopen, METH_VARARGS,
|
||||
"open(path[, flag[, mode]]) -> mapping\n"
|
||||
"Return a database object."},
|
||||
DBMOPEN_METHODDEF
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
|
@ -4,25 +4,54 @@
|
||||
#define GET_WEAKREFS_LISTPTR(o) \
|
||||
((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
|
||||
|
||||
/*[clinic]
|
||||
|
||||
PyDoc_STRVAR(weakref_getweakrefcount__doc__,
|
||||
"getweakrefcount(object) -- return the number of weak references\n"
|
||||
"to 'object'.");
|
||||
module _weakref
|
||||
|
||||
_weakref.getweakrefcount -> Py_ssize_t
|
||||
|
||||
object: object
|
||||
/
|
||||
|
||||
Return the number of weak references to 'object'.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(_weakref_getweakrefcount__doc__,
|
||||
"Return the number of weak references to \'object\'.\n"
|
||||
"\n"
|
||||
"_weakref.getweakrefcount(object)");
|
||||
|
||||
#define _WEAKREF_GETWEAKREFCOUNT_METHODDEF \
|
||||
{"getweakrefcount", (PyCFunction)_weakref_getweakrefcount, METH_O, _weakref_getweakrefcount__doc__},
|
||||
|
||||
static Py_ssize_t
|
||||
_weakref_getweakrefcount_impl(PyObject *self, PyObject *object);
|
||||
|
||||
static PyObject *
|
||||
weakref_getweakrefcount(PyObject *self, PyObject *object)
|
||||
_weakref_getweakrefcount(PyObject *self, PyObject *object)
|
||||
{
|
||||
PyObject *result = NULL;
|
||||
PyObject *return_value = NULL;
|
||||
Py_ssize_t _return_value;
|
||||
_return_value = _weakref_getweakrefcount_impl(self, object);
|
||||
if ((_return_value == -1) && PyErr_Occurred())
|
||||
goto exit;
|
||||
return_value = PyLong_FromSsize_t(_return_value);
|
||||
|
||||
if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
|
||||
PyWeakReference **list = GET_WEAKREFS_LISTPTR(object);
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
result = PyLong_FromSsize_t(_PyWeakref_GetWeakrefCount(*list));
|
||||
}
|
||||
else
|
||||
result = PyLong_FromLong(0);
|
||||
static Py_ssize_t
|
||||
_weakref_getweakrefcount_impl(PyObject *self, PyObject *object)
|
||||
/*[clinic checksum: 0b7e7ddd87d483719ebac0fba364fff0ed0182d9]*/
|
||||
{
|
||||
PyWeakReference **list;
|
||||
|
||||
return result;
|
||||
if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(object)))
|
||||
return 0;
|
||||
|
||||
list = GET_WEAKREFS_LISTPTR(object);
|
||||
return _PyWeakref_GetWeakrefCount(*list);
|
||||
}
|
||||
|
||||
|
||||
@ -78,8 +107,7 @@ weakref_proxy(PyObject *self, PyObject *args)
|
||||
|
||||
static PyMethodDef
|
||||
weakref_functions[] = {
|
||||
{"getweakrefcount", weakref_getweakrefcount, METH_O,
|
||||
weakref_getweakrefcount__doc__},
|
||||
_WEAKREF_GETWEAKREFCOUNT_METHODDEF
|
||||
{"getweakrefs", weakref_getweakrefs, METH_O,
|
||||
weakref_getweakrefs__doc__},
|
||||
{"proxy", weakref_proxy, METH_VARARGS,
|
||||
@ -106,7 +134,7 @@ PyInit__weakref(void)
|
||||
PyObject *m;
|
||||
|
||||
m = PyModule_Create(&weakrefmodule);
|
||||
|
||||
|
||||
if (m != NULL) {
|
||||
Py_INCREF(&_PyWeakref_RefType);
|
||||
PyModule_AddObject(m, "ref",
|
||||
|
@ -8,6 +8,8 @@
|
||||
of the compiler used. Different compilers define their own feature
|
||||
test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */
|
||||
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
/*
|
||||
* Step 1 of support for weak-linking a number of symbols existing on
|
||||
@ -712,7 +714,7 @@ dir_fd_converter(PyObject *o, void *p)
|
||||
* path.function_name
|
||||
* If non-NULL, path_converter will use that as the name
|
||||
* of the function in error messages.
|
||||
* (If path.argument_name is NULL it omits the function name.)
|
||||
* (If path.function_name is NULL it omits the function name.)
|
||||
* path.argument_name
|
||||
* If non-NULL, path_converter will use that as the name
|
||||
* of the parameter in error messages.
|
||||
@ -776,6 +778,9 @@ typedef struct {
|
||||
PyObject *cleanup;
|
||||
} path_t;
|
||||
|
||||
#define PATH_T_INITIALIZE(function_name, nullable, allow_fd) \
|
||||
{function_name, NULL, nullable, allow_fd, NULL, NULL, 0, 0, NULL, NULL}
|
||||
|
||||
static void
|
||||
path_cleanup(path_t *path) {
|
||||
if (path->cleanup) {
|
||||
@ -1313,6 +1318,7 @@ path_error(path_t *path)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* POSIX generic methods */
|
||||
|
||||
static PyObject *
|
||||
@ -2347,48 +2353,145 @@ posix_do_stat(char *function_name, path_t *path,
|
||||
return _pystat_fromstructstat(&st);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_stat__doc__,
|
||||
"stat(path, *, dir_fd=None, follow_symlinks=True) -> stat result\n\n\
|
||||
Perform a stat system call on the given path.\n\
|
||||
\n\
|
||||
path may be specified as either a string or as an open file descriptor.\n\
|
||||
\n\
|
||||
If dir_fd is not None, it should be a file descriptor open to a directory,\n\
|
||||
and path should be relative; path will then be relative to that directory.\n\
|
||||
dir_fd may not be supported on your platform; if it is unavailable, using\n\
|
||||
it will raise a NotImplementedError.\n\
|
||||
If follow_symlinks is False, and the last element of the path is a symbolic\n\
|
||||
link, stat will examine the symbolic link itself instead of the file the\n\
|
||||
link points to.\n\
|
||||
It is an error to use dir_fd or follow_symlinks when specifying path as\n\
|
||||
an open file descriptor.");
|
||||
#ifdef HAVE_FSTATAT
|
||||
#define OS_STAT_DIR_FD_CONVERTER dir_fd_converter
|
||||
#else
|
||||
#define OS_STAT_DIR_FD_CONVERTER dir_fd_unavailable
|
||||
#endif
|
||||
|
||||
|
||||
/*[python]
|
||||
|
||||
class path_t_converter(CConverter):
|
||||
|
||||
type = "path_t"
|
||||
impl_by_reference = True
|
||||
parse_by_reference = True
|
||||
|
||||
converter = 'path_converter'
|
||||
|
||||
def converter_init(self, *, allow_fd=False, nullable=False):
|
||||
def strify(value):
|
||||
return str(int(bool(value)))
|
||||
|
||||
# right now path_t doesn't support default values.
|
||||
# to support a default value, you'll need to override initialize().
|
||||
|
||||
assert self.default is unspecified
|
||||
|
||||
self.nullable = nullable
|
||||
self.allow_fd = allow_fd
|
||||
|
||||
self.c_default = 'PATH_T_INITIALIZE("{}", {}, {})'.format(
|
||||
self.function.name,
|
||||
strify(nullable),
|
||||
strify(allow_fd),
|
||||
)
|
||||
|
||||
def cleanup(self):
|
||||
return "path_cleanup(&" + self.name + ");\n"
|
||||
|
||||
|
||||
class dir_fd_converter(CConverter):
|
||||
type = 'int'
|
||||
converter = 'OS_STAT_DIR_FD_CONVERTER'
|
||||
|
||||
def converter_init(self):
|
||||
if self.default in (unspecified, None):
|
||||
self.c_default = 'DEFAULT_DIR_FD'
|
||||
|
||||
|
||||
[python]*/
|
||||
/*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
|
||||
|
||||
/*[clinic]
|
||||
module os
|
||||
|
||||
os.stat -> object(doc_default='stat_result')
|
||||
|
||||
path : path_t(allow_fd=True)
|
||||
Path to be examined; can be string, bytes, or open-file-descriptor int.
|
||||
|
||||
*
|
||||
|
||||
dir_fd : dir_fd = None
|
||||
If not None, it should be a file descriptor open to a directory,
|
||||
and path should be a relative string; path will then be relative to
|
||||
that directory.
|
||||
|
||||
follow_symlinks: bool = True
|
||||
If False, and the last element of the path is a symbolic link,
|
||||
stat will examine the symbolic link itself instead of the file
|
||||
the link points to.
|
||||
|
||||
Perform a stat system call on the given path.
|
||||
|
||||
dir_fd and follow_symlinks may not be implemented
|
||||
on your platform. If they are unavailable, using them will raise a
|
||||
NotImplementedError.
|
||||
|
||||
It's an error to use dir_fd or follow_symlinks when specifying path as
|
||||
an open file descriptor.
|
||||
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(os_stat__doc__,
|
||||
"Perform a stat system call on the given path.\n"
|
||||
"\n"
|
||||
"os.stat(path, *, dir_fd=None, follow_symlinks=True) -> stat_result\n"
|
||||
" path\n"
|
||||
" Path to be examined; can be string, bytes, or open-file-descriptor int.\n"
|
||||
" dir_fd\n"
|
||||
" If not None, it should be a file descriptor open to a directory,\n"
|
||||
" and path should be a relative string; path will then be relative to\n"
|
||||
" that directory.\n"
|
||||
" follow_symlinks\n"
|
||||
" If False, and the last element of the path is a symbolic link,\n"
|
||||
" stat will examine the symbolic link itself instead of the file\n"
|
||||
" the link points to.\n"
|
||||
"\n"
|
||||
"dir_fd and follow_symlinks may not be implemented\n"
|
||||
" on your platform. If they are unavailable, using them will raise a\n"
|
||||
" NotImplementedError.\n"
|
||||
"\n"
|
||||
"It\'s an error to use dir_fd or follow_symlinks when specifying path as\n"
|
||||
" an open file descriptor.");
|
||||
|
||||
#define OS_STAT_METHODDEF \
|
||||
{"stat", (PyCFunction)os_stat, METH_VARARGS|METH_KEYWORDS, os_stat__doc__},
|
||||
|
||||
static PyObject *
|
||||
posix_stat(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
os_stat_impl(PyObject *self, path_t *path, int dir_fd, int follow_symlinks);
|
||||
|
||||
static PyObject *
|
||||
os_stat(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *keywords[] = {"path", "dir_fd", "follow_symlinks", NULL};
|
||||
path_t path;
|
||||
PyObject *return_value = NULL;
|
||||
static char *_keywords[] = {"path", "dir_fd", "follow_symlinks", NULL};
|
||||
path_t path = PATH_T_INITIALIZE("stat", 0, 1);
|
||||
int dir_fd = DEFAULT_DIR_FD;
|
||||
int follow_symlinks = 1;
|
||||
PyObject *return_value;
|
||||
|
||||
memset(&path, 0, sizeof(path));
|
||||
path.function_name = "stat";
|
||||
path.allow_fd = 1;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&p:stat", keywords,
|
||||
path_converter, &path,
|
||||
#ifdef HAVE_FSTATAT
|
||||
dir_fd_converter, &dir_fd,
|
||||
#else
|
||||
dir_fd_unavailable, &dir_fd,
|
||||
#endif
|
||||
&follow_symlinks))
|
||||
return NULL;
|
||||
return_value = posix_do_stat("stat", &path, dir_fd, follow_symlinks);
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
|
||||
"O&|$O&p:stat", _keywords,
|
||||
path_converter, &path, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &follow_symlinks))
|
||||
goto exit;
|
||||
return_value = os_stat_impl(self, &path, dir_fd, follow_symlinks);
|
||||
|
||||
exit:
|
||||
/* Cleanup for path */
|
||||
path_cleanup(&path);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
os_stat_impl(PyObject *self, path_t *path, int dir_fd, int follow_symlinks)
|
||||
/*[clinic checksum: 9d9af08e8cfafd12f94e73ea3065eb3056f99515]*/
|
||||
{
|
||||
return posix_do_stat("stat", path, dir_fd, follow_symlinks);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_lstat__doc__,
|
||||
"lstat(path, *, dir_fd=None) -> stat result\n\n\
|
||||
Like stat(), but do not follow symbolic links.\n\
|
||||
@ -2414,44 +2517,120 @@ posix_lstat(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
#endif
|
||||
))
|
||||
return NULL;
|
||||
return_value = posix_do_stat("stat", &path, dir_fd, follow_symlinks);
|
||||
return_value = posix_do_stat("lstat", &path, dir_fd, follow_symlinks);
|
||||
path_cleanup(&path);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(posix_access__doc__,
|
||||
"access(path, mode, *, dir_fd=None, effective_ids=False,\
|
||||
follow_symlinks=True)\n\n\
|
||||
Use the real uid/gid to test for access to a path. Returns True if granted,\n\
|
||||
False otherwise.\n\
|
||||
\n\
|
||||
If dir_fd is not None, it should be a file descriptor open to a directory,\n\
|
||||
and path should be relative; path will then be relative to that directory.\n\
|
||||
If effective_ids is True, access will use the effective uid/gid instead of\n\
|
||||
the real uid/gid.\n\
|
||||
If follow_symlinks is False, and the last element of the path is a symbolic\n\
|
||||
link, access will examine the symbolic link itself instead of the file the\n\
|
||||
link points to.\n\
|
||||
dir_fd, effective_ids, and follow_symlinks may not be implemented\n\
|
||||
on your platform. If they are unavailable, using them will raise a\n\
|
||||
NotImplementedError.\n\
|
||||
\n\
|
||||
Note that most operations will use the effective uid/gid, therefore this\n\
|
||||
routine can be used in a suid/sgid environment to test if the invoking user\n\
|
||||
has the specified access to the path.\n\
|
||||
The mode argument can be F_OK to test existence, or the inclusive-OR\n\
|
||||
of R_OK, W_OK, and X_OK.");
|
||||
|
||||
#ifdef HAVE_FACCESSAT
|
||||
#define OS_ACCESS_DIR_FD_CONVERTER dir_fd_converter
|
||||
#else
|
||||
#define OS_ACCESS_DIR_FD_CONVERTER dir_fd_unavailable
|
||||
#endif
|
||||
/*[clinic]
|
||||
os.access -> object(doc_default='True if granted, False otherwise')
|
||||
|
||||
path: path_t(allow_fd=True)
|
||||
Path to be tested; can be string, bytes, or open-file-descriptor int.
|
||||
|
||||
mode: int
|
||||
Operating-system mode bitfield. Can be F_OK to test existence,
|
||||
or the inclusive-OR of R_OK, W_OK, and X_OK.
|
||||
|
||||
*
|
||||
|
||||
dir_fd : dir_fd = None
|
||||
If not None, it should be a file descriptor open to a directory,
|
||||
and path should be relative; path will then be relative to that
|
||||
directory.
|
||||
|
||||
effective_ids: bool = False
|
||||
If True, access will use the effective uid/gid instead of
|
||||
the real uid/gid.
|
||||
|
||||
follow_symlinks: bool = True
|
||||
If False, and the last element of the path is a symbolic link,
|
||||
access will examine the symbolic link itself instead of the file
|
||||
the link points to.
|
||||
|
||||
Use the real uid/gid to test for access to a path.
|
||||
|
||||
{parameters}
|
||||
dir_fd, effective_ids, and follow_symlinks may not be implemented
|
||||
on your platform. If they are unavailable, using them will raise a
|
||||
NotImplementedError.
|
||||
|
||||
Note that most operations will use the effective uid/gid, therefore this
|
||||
routine can be used in a suid/sgid environment to test if the invoking user
|
||||
has the specified access to the path.
|
||||
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(os_access__doc__,
|
||||
"Use the real uid/gid to test for access to a path.\n"
|
||||
"\n"
|
||||
"os.access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True) -> True if granted, False otherwise\n"
|
||||
" path\n"
|
||||
" Path to be tested; can be string, bytes, or open-file-descriptor int.\n"
|
||||
" mode\n"
|
||||
" Operating-system mode bitfield. Can be F_OK to test existence,\n"
|
||||
" or the inclusive-OR of R_OK, W_OK, and X_OK.\n"
|
||||
" dir_fd\n"
|
||||
" If not None, it should be a file descriptor open to a directory,\n"
|
||||
" and path should be relative; path will then be relative to that\n"
|
||||
" directory.\n"
|
||||
" effective_ids\n"
|
||||
" If True, access will use the effective uid/gid instead of\n"
|
||||
" the real uid/gid.\n"
|
||||
" follow_symlinks\n"
|
||||
" If False, and the last element of the path is a symbolic link,\n"
|
||||
" access will examine the symbolic link itself instead of the file\n"
|
||||
" the link points to.\n"
|
||||
"\n"
|
||||
"{parameters}\n"
|
||||
"dir_fd, effective_ids, and follow_symlinks may not be implemented\n"
|
||||
" on your platform. If they are unavailable, using them will raise a\n"
|
||||
" NotImplementedError.\n"
|
||||
"\n"
|
||||
"Note that most operations will use the effective uid/gid, therefore this\n"
|
||||
" routine can be used in a suid/sgid environment to test if the invoking user\n"
|
||||
" has the specified access to the path.");
|
||||
|
||||
#define OS_ACCESS_METHODDEF \
|
||||
{"access", (PyCFunction)os_access, METH_VARARGS|METH_KEYWORDS, os_access__doc__},
|
||||
|
||||
static PyObject *
|
||||
posix_access(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
os_access_impl(PyObject *self, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks);
|
||||
|
||||
static PyObject *
|
||||
os_access(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
static char *keywords[] = {"path", "mode", "dir_fd", "effective_ids",
|
||||
"follow_symlinks", NULL};
|
||||
path_t path;
|
||||
PyObject *return_value = NULL;
|
||||
static char *_keywords[] = {"path", "mode", "dir_fd", "effective_ids", "follow_symlinks", NULL};
|
||||
path_t path = PATH_T_INITIALIZE("access", 0, 1);
|
||||
int mode;
|
||||
int dir_fd = DEFAULT_DIR_FD;
|
||||
int effective_ids = 0;
|
||||
int follow_symlinks = 1;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
|
||||
"O&i|$O&pp:access", _keywords,
|
||||
path_converter, &path, &mode, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &effective_ids, &follow_symlinks))
|
||||
goto exit;
|
||||
return_value = os_access_impl(self, &path, mode, dir_fd, effective_ids, follow_symlinks);
|
||||
|
||||
exit:
|
||||
/* Cleanup for path */
|
||||
path_cleanup(&path);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
os_access_impl(PyObject *self, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks)
|
||||
/*[clinic checksum: 0147557eb43243df57ba616cc7c35f232c69bc6a]*/
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
@ -2460,17 +2639,6 @@ posix_access(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
int result;
|
||||
#endif
|
||||
|
||||
memset(&path, 0, sizeof(path));
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i|$O&pp:access", keywords,
|
||||
path_converter, &path, &mode,
|
||||
#ifdef HAVE_FACCESSAT
|
||||
dir_fd_converter, &dir_fd,
|
||||
#else
|
||||
dir_fd_unavailable, &dir_fd,
|
||||
#endif
|
||||
&effective_ids, &follow_symlinks))
|
||||
return NULL;
|
||||
|
||||
#ifndef HAVE_FACCESSAT
|
||||
if (follow_symlinks_specified("access", follow_symlinks))
|
||||
goto exit;
|
||||
@ -2514,11 +2682,11 @@ posix_access(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
flags |= AT_SYMLINK_NOFOLLOW;
|
||||
if (effective_ids)
|
||||
flags |= AT_EACCESS;
|
||||
result = faccessat(dir_fd, path.narrow, mode, flags);
|
||||
result = faccessat(dir_fd, path->narrow, mode, flags);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
result = access(path.narrow, mode);
|
||||
result = access(path->narrow, mode);
|
||||
Py_END_ALLOW_THREADS
|
||||
return_value = PyBool_FromLong(!result);
|
||||
#endif
|
||||
@ -2526,7 +2694,6 @@ posix_access(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
#ifndef HAVE_FACCESSAT
|
||||
exit:
|
||||
#endif
|
||||
path_cleanup(&path);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
@ -2543,35 +2710,76 @@ exit:
|
||||
#define X_OK 1
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_TTYNAME
|
||||
PyDoc_STRVAR(posix_ttyname__doc__,
|
||||
"ttyname(fd) -> string\n\n\
|
||||
Return the name of the terminal device connected to 'fd'.");
|
||||
|
||||
/*[clinic]
|
||||
os.ttyname -> DecodeFSDefault
|
||||
|
||||
fd: int
|
||||
Integer file descriptor handle.
|
||||
|
||||
/
|
||||
|
||||
Return the name of the terminal device connected to 'fd'.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(os_ttyname__doc__,
|
||||
"Return the name of the terminal device connected to \'fd\'.\n"
|
||||
"\n"
|
||||
"os.ttyname(fd)\n"
|
||||
" fd\n"
|
||||
" Integer file descriptor handle.");
|
||||
|
||||
#define OS_TTYNAME_METHODDEF \
|
||||
{"ttyname", (PyCFunction)os_ttyname, METH_VARARGS, os_ttyname__doc__},
|
||||
|
||||
static char *
|
||||
os_ttyname_impl(PyObject *self, int fd);
|
||||
|
||||
static PyObject *
|
||||
posix_ttyname(PyObject *self, PyObject *args)
|
||||
os_ttyname(PyObject *self, PyObject *args)
|
||||
{
|
||||
int id;
|
||||
char *ret;
|
||||
PyObject *return_value = NULL;
|
||||
int fd;
|
||||
char *_return_value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:ttyname", &id))
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"i:ttyname",
|
||||
&fd))
|
||||
goto exit;
|
||||
_return_value = os_ttyname_impl(self, fd);
|
||||
if (_return_value == NULL)
|
||||
goto exit;
|
||||
return_value = PyUnicode_DecodeFSDefault(_return_value);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static char *
|
||||
os_ttyname_impl(PyObject *self, int fd)
|
||||
/*[clinic checksum: ea680155d87bb733f542d67653eca732dd0981a8]*/
|
||||
{
|
||||
char *ret;
|
||||
|
||||
#if defined(__VMS)
|
||||
/* file descriptor 0 only, the default input device (stdin) */
|
||||
if (id == 0) {
|
||||
if (fd == 0) {
|
||||
ret = ttyname();
|
||||
}
|
||||
else {
|
||||
ret = NULL;
|
||||
}
|
||||
#else
|
||||
ret = ttyname(id);
|
||||
ret = ttyname(fd);
|
||||
#endif
|
||||
if (ret == NULL)
|
||||
return posix_error();
|
||||
return PyUnicode_DecodeFSDefault(ret);
|
||||
posix_error();
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#define OS_TTYNAME_METHODDEF
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CTERMID
|
||||
@ -10912,13 +11120,13 @@ posix_set_handle_inheritable(PyObject *self, PyObject *args)
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
|
||||
|
||||
static PyMethodDef posix_methods[] = {
|
||||
{"access", (PyCFunction)posix_access,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
posix_access__doc__},
|
||||
#ifdef HAVE_TTYNAME
|
||||
{"ttyname", posix_ttyname, METH_VARARGS, posix_ttyname__doc__},
|
||||
#endif
|
||||
|
||||
OS_STAT_METHODDEF
|
||||
OS_ACCESS_METHODDEF
|
||||
OS_TTYNAME_METHODDEF
|
||||
|
||||
{"chdir", (PyCFunction)posix_chdir,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
posix_chdir__doc__},
|
||||
@ -11002,9 +11210,6 @@ static PyMethodDef posix_methods[] = {
|
||||
{"rmdir", (PyCFunction)posix_rmdir,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
posix_rmdir__doc__},
|
||||
{"stat", (PyCFunction)posix_stat,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
posix_stat__doc__},
|
||||
{"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__},
|
||||
#if defined(HAVE_SYMLINK)
|
||||
{"symlink", (PyCFunction)posix_symlink,
|
||||
|
@ -107,24 +107,62 @@ static Py_UCS4 getuchar(PyUnicodeObject *obj)
|
||||
|
||||
/* --- Module API --------------------------------------------------------- */
|
||||
|
||||
/*[clinic]
|
||||
module unicodedata
|
||||
unicodedata.decimal
|
||||
|
||||
unichr: object(type='str')
|
||||
default: object=NULL
|
||||
/
|
||||
|
||||
Converts a Unicode character into its equivalent decimal value.
|
||||
|
||||
Returns the decimal value assigned to the Unicode character unichr
|
||||
as integer. If no such value is defined, default is returned, or, if
|
||||
not given, ValueError is raised.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(unicodedata_decimal__doc__,
|
||||
"decimal(unichr[, default])\n\
|
||||
\n\
|
||||
Returns the decimal value assigned to the Unicode character unichr\n\
|
||||
as integer. If no such value is defined, default is returned, or, if\n\
|
||||
not given, ValueError is raised.");
|
||||
"Converts a Unicode character into its equivalent decimal value.\n"
|
||||
"\n"
|
||||
"unicodedata.decimal(unichr, default=None)\n"
|
||||
"\n"
|
||||
"Returns the decimal value assigned to the Unicode character unichr\n"
|
||||
"as integer. If no such value is defined, default is returned, or, if\n"
|
||||
"not given, ValueError is raised.");
|
||||
|
||||
#define UNICODEDATA_DECIMAL_METHODDEF \
|
||||
{"decimal", (PyCFunction)unicodedata_decimal, METH_VARARGS, unicodedata_decimal__doc__},
|
||||
|
||||
static PyObject *
|
||||
unicodedata_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value);
|
||||
|
||||
static PyObject *
|
||||
unicodedata_decimal(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyUnicodeObject *v;
|
||||
PyObject *defobj = NULL;
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *unichr;
|
||||
PyObject *default_value = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O!|O:decimal",
|
||||
&PyUnicode_Type, &unichr, &default_value))
|
||||
goto exit;
|
||||
return_value = unicodedata_decimal_impl(self, unichr, default_value);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
unicodedata_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value)
|
||||
/*[clinic checksum: 76c8d1c3dbee495d4cfd86ca6829543a3129344a]*/
|
||||
{
|
||||
PyUnicodeObject *v = (PyUnicodeObject *)unichr;
|
||||
int have_old = 0;
|
||||
long rc;
|
||||
Py_UCS4 c;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!|O:decimal", &PyUnicode_Type, &v, &defobj))
|
||||
return NULL;
|
||||
c = getuchar(v);
|
||||
if (c == (Py_UCS4)-1)
|
||||
return NULL;
|
||||
@ -145,14 +183,14 @@ unicodedata_decimal(PyObject *self, PyObject *args)
|
||||
if (!have_old)
|
||||
rc = Py_UNICODE_TODECIMAL(c);
|
||||
if (rc < 0) {
|
||||
if (defobj == NULL) {
|
||||
if (default_value == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"not a decimal");
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
Py_INCREF(defobj);
|
||||
return defobj;
|
||||
Py_INCREF(default_value);
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
return PyLong_FromLong(rc);
|
||||
@ -1250,7 +1288,7 @@ unicodedata_lookup(PyObject* self, PyObject* args)
|
||||
/* XXX Add doc strings. */
|
||||
|
||||
static PyMethodDef unicodedata_functions[] = {
|
||||
{"decimal", unicodedata_decimal, METH_VARARGS, unicodedata_decimal__doc__},
|
||||
UNICODEDATA_DECIMAL_METHODDEF
|
||||
{"digit", unicodedata_digit, METH_VARARGS, unicodedata_digit__doc__},
|
||||
{"numeric", unicodedata_numeric, METH_VARARGS, unicodedata_numeric__doc__},
|
||||
{"category", unicodedata_category, METH_VARARGS,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "structmember.h"
|
||||
#include "zlib.h"
|
||||
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
#include "pythread.h"
|
||||
#define ENTER_ZLIB(obj) \
|
||||
@ -626,87 +627,136 @@ save_unconsumed_input(compobject *self, int err)
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(decomp_decompress__doc__,
|
||||
"decompress(data, max_length) -- Return a string containing the decompressed\n"
|
||||
"version of the data.\n"
|
||||
/*[clinic]
|
||||
|
||||
module zlib
|
||||
|
||||
zlib.decompress
|
||||
|
||||
data: Py_buffer
|
||||
The binary data to decompress.
|
||||
max_length: int = 0
|
||||
The maximum allowable length of the decompressed data.
|
||||
Unconsumed input data will be stored in
|
||||
the unconsumed_tail attribute.
|
||||
/
|
||||
|
||||
Return a string containing the decompressed version of the data.
|
||||
|
||||
After calling this function, some of the input data may still be stored in
|
||||
internal buffers for later processing.
|
||||
Call the flush() method to clear these buffers.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(zlib_decompress__doc__,
|
||||
"Return a string containing the decompressed version of the data.\n"
|
||||
"\n"
|
||||
"zlib.decompress(data, max_length=0)\n"
|
||||
" data\n"
|
||||
" The binary data to decompress.\n"
|
||||
" max_length\n"
|
||||
" The maximum allowable length of the decompressed data.\n"
|
||||
" Unconsumed input data will be stored in\n"
|
||||
" the unconsumed_tail attribute.\n"
|
||||
"\n"
|
||||
"After calling this function, some of the input data may still be stored in\n"
|
||||
"internal buffers for later processing.\n"
|
||||
"Call the flush() method to clear these buffers.\n"
|
||||
"If the max_length parameter is specified then the return value will be\n"
|
||||
"no longer than max_length. Unconsumed input data will be stored in\n"
|
||||
"the unconsumed_tail attribute.");
|
||||
"Call the flush() method to clear these buffers.");
|
||||
|
||||
#define ZLIB_DECOMPRESS_METHODDEF \
|
||||
{"decompress", (PyCFunction)zlib_decompress, METH_VARARGS, zlib_decompress__doc__},
|
||||
|
||||
static PyObject *
|
||||
PyZlib_objdecompress(compobject *self, PyObject *args)
|
||||
zlib_decompress_impl(PyObject *self, Py_buffer *data, int max_length);
|
||||
|
||||
static PyObject *
|
||||
zlib_decompress(PyObject *self, PyObject *args)
|
||||
{
|
||||
int err, max_length = 0;
|
||||
PyObject *return_value = NULL;
|
||||
Py_buffer data;
|
||||
int max_length = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"y*|i:decompress",
|
||||
&data, &max_length))
|
||||
goto exit;
|
||||
return_value = zlib_decompress_impl(self, &data, max_length);
|
||||
|
||||
exit:
|
||||
/* Cleanup for data */
|
||||
PyBuffer_Release(&data);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
zlib_decompress_impl(PyObject *self, Py_buffer *data, int max_length)
|
||||
/*[clinic checksum: 168d093d400739dde947cca1f4fb0f9d51cdc2c9]*/
|
||||
{
|
||||
compobject *zself = (compobject *)self;
|
||||
int err;
|
||||
unsigned int inplen;
|
||||
Py_ssize_t old_length, length = DEFAULTALLOC;
|
||||
PyObject *RetVal = NULL;
|
||||
Py_buffer pinput;
|
||||
Byte *input;
|
||||
unsigned long start_total_out;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput,
|
||||
&max_length))
|
||||
return NULL;
|
||||
if (pinput.len > UINT_MAX) {
|
||||
if (data->len > UINT_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Size does not fit in an unsigned int");
|
||||
goto error_outer;
|
||||
return NULL;
|
||||
}
|
||||
input = pinput.buf;
|
||||
inplen = pinput.len;
|
||||
input = data->buf;
|
||||
inplen = data->len;
|
||||
if (max_length < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"max_length must be greater than zero");
|
||||
goto error_outer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* limit amount of data allocated to max_length */
|
||||
if (max_length && length > max_length)
|
||||
length = max_length;
|
||||
if (!(RetVal = PyBytes_FromStringAndSize(NULL, length)))
|
||||
goto error_outer;
|
||||
return NULL;
|
||||
|
||||
ENTER_ZLIB(self);
|
||||
ENTER_ZLIB(zself);
|
||||
|
||||
start_total_out = self->zst.total_out;
|
||||
self->zst.avail_in = inplen;
|
||||
self->zst.next_in = input;
|
||||
self->zst.avail_out = length;
|
||||
self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal);
|
||||
start_total_out = zself->zst.total_out;
|
||||
zself->zst.avail_in = inplen;
|
||||
zself->zst.next_in = input;
|
||||
zself->zst.avail_out = length;
|
||||
zself->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
err = inflate(&(self->zst), Z_SYNC_FLUSH);
|
||||
err = inflate(&(zself->zst), Z_SYNC_FLUSH);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (err == Z_NEED_DICT && self->zdict != NULL) {
|
||||
if (err == Z_NEED_DICT && zself->zdict != NULL) {
|
||||
Py_buffer zdict_buf;
|
||||
if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
|
||||
if (PyObject_GetBuffer(zself->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
|
||||
Py_DECREF(RetVal);
|
||||
RetVal = NULL;
|
||||
goto error;
|
||||
}
|
||||
err = inflateSetDictionary(&(self->zst), zdict_buf.buf, zdict_buf.len);
|
||||
err = inflateSetDictionary(&(zself->zst), zdict_buf.buf, zdict_buf.len);
|
||||
PyBuffer_Release(&zdict_buf);
|
||||
if (err != Z_OK) {
|
||||
zlib_error(self->zst, err, "while decompressing data");
|
||||
zlib_error(zself->zst, err, "while decompressing data");
|
||||
Py_DECREF(RetVal);
|
||||
RetVal = NULL;
|
||||
goto error;
|
||||
}
|
||||
/* Repeat the call to inflate. */
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
err = inflate(&(self->zst), Z_SYNC_FLUSH);
|
||||
err = inflate(&(zself->zst), Z_SYNC_FLUSH);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
|
||||
/* While Z_OK and the output buffer is full, there might be more output.
|
||||
So extend the output buffer and try again.
|
||||
*/
|
||||
while (err == Z_OK && self->zst.avail_out == 0) {
|
||||
while (err == Z_OK && zself->zst.avail_out == 0) {
|
||||
/* If max_length set, don't continue decompressing if we've already
|
||||
reached the limit.
|
||||
*/
|
||||
@ -723,16 +773,16 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
|
||||
Py_CLEAR(RetVal);
|
||||
goto error;
|
||||
}
|
||||
self->zst.next_out =
|
||||
zself->zst.next_out =
|
||||
(unsigned char *)PyBytes_AS_STRING(RetVal) + old_length;
|
||||
self->zst.avail_out = length - old_length;
|
||||
zself->zst.avail_out = length - old_length;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
err = inflate(&(self->zst), Z_SYNC_FLUSH);
|
||||
err = inflate(&(zself->zst), Z_SYNC_FLUSH);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
|
||||
if (save_unconsumed_input(self, err) < 0) {
|
||||
if (save_unconsumed_input(zself, err) < 0) {
|
||||
Py_DECREF(RetVal);
|
||||
RetVal = NULL;
|
||||
goto error;
|
||||
@ -741,26 +791,24 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
|
||||
if (err == Z_STREAM_END) {
|
||||
/* This is the logical place to call inflateEnd, but the old behaviour
|
||||
of only calling it on flush() is preserved. */
|
||||
self->eof = 1;
|
||||
zself->eof = 1;
|
||||
} else if (err != Z_OK && err != Z_BUF_ERROR) {
|
||||
/* We will only get Z_BUF_ERROR if the output buffer was full
|
||||
but there wasn't more output when we tried again, so it is
|
||||
not an error condition.
|
||||
*/
|
||||
zlib_error(self->zst, err, "while decompressing data");
|
||||
zlib_error(zself->zst, err, "while decompressing data");
|
||||
Py_DECREF(RetVal);
|
||||
RetVal = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) {
|
||||
if (_PyBytes_Resize(&RetVal, zself->zst.total_out - start_total_out) < 0) {
|
||||
Py_CLEAR(RetVal);
|
||||
}
|
||||
|
||||
error:
|
||||
LEAVE_ZLIB(self);
|
||||
error_outer:
|
||||
PyBuffer_Release(&pinput);
|
||||
LEAVE_ZLIB(zself);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
@ -856,12 +904,27 @@ PyZlib_flush(compobject *self, PyObject *args)
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB_COPY
|
||||
PyDoc_STRVAR(comp_copy__doc__,
|
||||
"copy() -- Return a copy of the compression object.");
|
||||
|
||||
/*[clinic]
|
||||
|
||||
zlib.copy
|
||||
|
||||
Return a copy of the compression object.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(zlib_copy__doc__,
|
||||
"Return a copy of the compression object.\n"
|
||||
"\n"
|
||||
"zlib.copy()");
|
||||
|
||||
#define ZLIB_COPY_METHODDEF \
|
||||
{"copy", (PyCFunction)zlib_copy, METH_NOARGS, zlib_copy__doc__},
|
||||
|
||||
static PyObject *
|
||||
PyZlib_copy(compobject *self)
|
||||
zlib_copy(PyObject *self)
|
||||
/*[clinic checksum: 7b648de2c1f933ba2b9fa17331ff1a44d9a4a740]*/
|
||||
{
|
||||
compobject *zself = (compobject *)self;
|
||||
compobject *retval = NULL;
|
||||
int err;
|
||||
|
||||
@ -871,8 +934,8 @@ PyZlib_copy(compobject *self)
|
||||
/* Copy the zstream state
|
||||
* We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe
|
||||
*/
|
||||
ENTER_ZLIB(self);
|
||||
err = deflateCopy(&retval->zst, &self->zst);
|
||||
ENTER_ZLIB(zself);
|
||||
err = deflateCopy(&retval->zst, &zself->zst);
|
||||
switch(err) {
|
||||
case(Z_OK):
|
||||
break;
|
||||
@ -884,28 +947,28 @@ PyZlib_copy(compobject *self)
|
||||
"Can't allocate memory for compression object");
|
||||
goto error;
|
||||
default:
|
||||
zlib_error(self->zst, err, "while copying compression object");
|
||||
zlib_error(zself->zst, err, "while copying compression object");
|
||||
goto error;
|
||||
}
|
||||
Py_INCREF(self->unused_data);
|
||||
Py_INCREF(self->unconsumed_tail);
|
||||
Py_XINCREF(self->zdict);
|
||||
Py_INCREF(zself->unused_data);
|
||||
Py_INCREF(zself->unconsumed_tail);
|
||||
Py_XINCREF(zself->zdict);
|
||||
Py_XDECREF(retval->unused_data);
|
||||
Py_XDECREF(retval->unconsumed_tail);
|
||||
Py_XDECREF(retval->zdict);
|
||||
retval->unused_data = self->unused_data;
|
||||
retval->unconsumed_tail = self->unconsumed_tail;
|
||||
retval->zdict = self->zdict;
|
||||
retval->eof = self->eof;
|
||||
retval->unused_data = zself->unused_data;
|
||||
retval->unconsumed_tail = zself->unconsumed_tail;
|
||||
retval->zdict = zself->zdict;
|
||||
retval->eof = zself->eof;
|
||||
|
||||
/* Mark it as being initialized */
|
||||
retval->is_initialised = 1;
|
||||
|
||||
LEAVE_ZLIB(self);
|
||||
LEAVE_ZLIB(zself);
|
||||
return (PyObject *)retval;
|
||||
|
||||
error:
|
||||
LEAVE_ZLIB(self);
|
||||
LEAVE_ZLIB(zself);
|
||||
Py_XDECREF(retval);
|
||||
return NULL;
|
||||
}
|
||||
@ -1055,16 +1118,14 @@ static PyMethodDef comp_methods[] =
|
||||
{"flush", (binaryfunc)PyZlib_flush, METH_VARARGS,
|
||||
comp_flush__doc__},
|
||||
#ifdef HAVE_ZLIB_COPY
|
||||
{"copy", (PyCFunction)PyZlib_copy, METH_NOARGS,
|
||||
comp_copy__doc__},
|
||||
ZLIB_COPY_METHODDEF
|
||||
#endif
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static PyMethodDef Decomp_methods[] =
|
||||
{
|
||||
{"decompress", (binaryfunc)PyZlib_objdecompress, METH_VARARGS,
|
||||
decomp_decompress__doc__},
|
||||
ZLIB_DECOMPRESS_METHODDEF
|
||||
{"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS,
|
||||
decomp_flush__doc__},
|
||||
#ifdef HAVE_ZLIB_COPY
|
||||
|
@ -2160,9 +2160,31 @@ dict_richcompare(PyObject *v, PyObject *w, int op)
|
||||
return res;
|
||||
}
|
||||
|
||||
/*[clinic]
|
||||
module dict
|
||||
|
||||
@coexist
|
||||
dict.__contains__
|
||||
|
||||
key: object
|
||||
/
|
||||
|
||||
True if D has a key k, else False"
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(dict___contains____doc__,
|
||||
"True if D has a key k, else False\"\n"
|
||||
"\n"
|
||||
"dict.__contains__(key)");
|
||||
|
||||
#define DICT___CONTAINS___METHODDEF \
|
||||
{"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__},
|
||||
|
||||
static PyObject *
|
||||
dict_contains(PyDictObject *mp, PyObject *key)
|
||||
dict___contains__(PyObject *self, PyObject *key)
|
||||
/*[clinic checksum: 61c5c802ea1d35699a1a754f1f3538ea9b259cf4]*/
|
||||
{
|
||||
register PyDictObject *mp = (PyDictObject *)self;
|
||||
Py_hash_t hash;
|
||||
PyDictKeyEntry *ep;
|
||||
PyObject **value_addr;
|
||||
@ -2447,9 +2469,6 @@ _PyDict_KeysSize(PyDictKeysObject *keys)
|
||||
return sizeof(PyDictKeysObject) + (DK_SIZE(keys)-1) * sizeof(PyDictKeyEntry);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(contains__doc__,
|
||||
"D.__contains__(k) -> True if D has a key k, else False");
|
||||
|
||||
PyDoc_STRVAR(getitem__doc__, "x.__getitem__(y) <==> x[y]");
|
||||
|
||||
PyDoc_STRVAR(sizeof__doc__,
|
||||
@ -2498,8 +2517,7 @@ PyDoc_STRVAR(values__doc__,
|
||||
"D.values() -> an object providing a view on D's values");
|
||||
|
||||
static PyMethodDef mapp_methods[] = {
|
||||
{"__contains__",(PyCFunction)dict_contains, METH_O | METH_COEXIST,
|
||||
contains__doc__},
|
||||
DICT___CONTAINS___METHODDEF
|
||||
{"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST,
|
||||
getitem__doc__},
|
||||
{"__sizeof__", (PyCFunction)dict_sizeof, METH_NOARGS,
|
||||
|
@ -12656,28 +12656,76 @@ unicode_swapcase(PyObject *self)
|
||||
return case_operation(self, do_swapcase);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(maketrans__doc__,
|
||||
"str.maketrans(x[, y[, z]]) -> dict (static method)\n\
|
||||
\n\
|
||||
Return a translation table usable for str.translate().\n\
|
||||
If there is only one argument, it must be a dictionary mapping Unicode\n\
|
||||
ordinals (integers) or characters to Unicode ordinals, strings or None.\n\
|
||||
Character keys will be then converted to ordinals.\n\
|
||||
If there are two arguments, they must be strings of equal length, and\n\
|
||||
in the resulting dictionary, each character in x will be mapped to the\n\
|
||||
character at the same position in y. If there is a third argument, it\n\
|
||||
must be a string, whose characters will be mapped to None in the result.");
|
||||
/*[clinic]
|
||||
module str
|
||||
|
||||
static PyObject*
|
||||
@staticmethod
|
||||
str.maketrans as unicode_maketrans
|
||||
|
||||
x: object
|
||||
|
||||
y: unicode=NULL
|
||||
|
||||
z: unicode=NULL
|
||||
|
||||
/
|
||||
|
||||
Return a translation table usable for str.translate().
|
||||
|
||||
If there is only one argument, it must be a dictionary mapping Unicode
|
||||
ordinals (integers) or characters to Unicode ordinals, strings or None.
|
||||
Character keys will be then converted to ordinals.
|
||||
If there are two arguments, they must be strings of equal length, and
|
||||
in the resulting dictionary, each character in x will be mapped to the
|
||||
character at the same position in y. If there is a third argument, it
|
||||
must be a string, whose characters will be mapped to None in the result.
|
||||
[clinic]*/
|
||||
|
||||
PyDoc_STRVAR(unicode_maketrans__doc__,
|
||||
"Return a translation table usable for str.translate().\n"
|
||||
"\n"
|
||||
"str.maketrans(x, y=None, z=None)\n"
|
||||
"\n"
|
||||
"If there is only one argument, it must be a dictionary mapping Unicode\n"
|
||||
"ordinals (integers) or characters to Unicode ordinals, strings or None.\n"
|
||||
"Character keys will be then converted to ordinals.\n"
|
||||
"If there are two arguments, they must be strings of equal length, and\n"
|
||||
"in the resulting dictionary, each character in x will be mapped to the\n"
|
||||
"character at the same position in y. If there is a third argument, it\n"
|
||||
"must be a string, whose characters will be mapped to None in the result.");
|
||||
|
||||
#define UNICODE_MAKETRANS_METHODDEF \
|
||||
{"maketrans", (PyCFunction)unicode_maketrans, METH_VARARGS|METH_STATIC, unicode_maketrans__doc__},
|
||||
|
||||
static PyObject *
|
||||
unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z);
|
||||
|
||||
static PyObject *
|
||||
unicode_maketrans(PyObject *null, PyObject *args)
|
||||
{
|
||||
PyObject *x, *y = NULL, *z = NULL;
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *x;
|
||||
PyObject *y = NULL;
|
||||
PyObject *z = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O|UU:maketrans",
|
||||
&x, &y, &z))
|
||||
goto exit;
|
||||
return_value = unicode_maketrans_impl(x, y, z);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z)
|
||||
/*[clinic checksum: 137db9c3199e7906b7967009f511c24fa3235b5f]*/
|
||||
{
|
||||
PyObject *new = NULL, *key, *value;
|
||||
Py_ssize_t i = 0;
|
||||
int res;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O|UU:maketrans", &x, &y, &z))
|
||||
return NULL;
|
||||
new = PyDict_New();
|
||||
if (!new)
|
||||
return NULL;
|
||||
@ -13317,8 +13365,7 @@ static PyMethodDef unicode_methods[] = {
|
||||
{"format", (PyCFunction) do_string_format, METH_VARARGS | METH_KEYWORDS, format__doc__},
|
||||
{"format_map", (PyCFunction) do_string_format_map, METH_O, format_map__doc__},
|
||||
{"__format__", (PyCFunction) unicode__format__, METH_VARARGS, p_format__doc__},
|
||||
{"maketrans", (PyCFunction) unicode_maketrans,
|
||||
METH_VARARGS | METH_STATIC, maketrans__doc__},
|
||||
UNICODE_MAKETRANS_METHODDEF
|
||||
{"__sizeof__", (PyCFunction) unicode__sizeof__, METH_NOARGS, sizeof__doc__},
|
||||
#if 0
|
||||
/* These methods are just used for debugging the implementation. */
|
||||
|
2477
Tools/clinic/clinic.py
Executable file
2477
Tools/clinic/clinic.py
Executable file
File diff suppressed because it is too large
Load Diff
699
Tools/clinic/clinic_test.py
Normal file
699
Tools/clinic/clinic_test.py
Normal file
@ -0,0 +1,699 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Argument Clinic
|
||||
# Copyright 2012-2013 by Larry Hastings.
|
||||
# Licensed to the PSF under a contributor agreement.
|
||||
#
|
||||
|
||||
import builtins
|
||||
import clinic
|
||||
from clinic import DSLParser
|
||||
import collections
|
||||
import inspect
|
||||
from test import support
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
|
||||
class FakeConverter:
|
||||
def __init__(self, name, args):
|
||||
self.name = name
|
||||
self.args = args
|
||||
|
||||
|
||||
class FakeConverterFactory:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __call__(self, name, default, **kwargs):
|
||||
return FakeConverter(self.name, kwargs)
|
||||
|
||||
|
||||
class FakeConvertersDict:
|
||||
def __init__(self):
|
||||
self.used_converters = {}
|
||||
|
||||
def get(self, name, default):
|
||||
return self.used_converters.setdefault(name, FakeConverterFactory(name))
|
||||
|
||||
class FakeClinic:
|
||||
def __init__(self):
|
||||
self.converters = FakeConvertersDict()
|
||||
self.legacy_converters = FakeConvertersDict()
|
||||
self.language = clinic.CLanguage()
|
||||
self.filename = None
|
||||
self.block_parser = clinic.BlockParser('', self.language)
|
||||
self.modules = collections.OrderedDict()
|
||||
clinic.clinic = self
|
||||
self.name = "FakeClinic"
|
||||
|
||||
def is_directive(self, name):
|
||||
return name == "module"
|
||||
|
||||
def directive(self, name, args):
|
||||
self.called_directives[name] = args
|
||||
|
||||
_module_and_class = clinic.Clinic._module_and_class
|
||||
|
||||
|
||||
|
||||
class ClinicGroupPermuterTest(TestCase):
|
||||
def _test(self, l, m, r, output):
|
||||
computed = clinic.permute_optional_groups(l, m, r)
|
||||
self.assertEqual(output, computed)
|
||||
|
||||
def test_range(self):
|
||||
self._test([['start']], ['stop'], [['step']],
|
||||
(
|
||||
('stop',),
|
||||
('start', 'stop',),
|
||||
('start', 'stop', 'step',),
|
||||
))
|
||||
|
||||
def test_add_window(self):
|
||||
self._test([['x', 'y']], ['ch'], [['attr']],
|
||||
(
|
||||
('ch',),
|
||||
('ch', 'attr'),
|
||||
('x', 'y', 'ch',),
|
||||
('x', 'y', 'ch', 'attr'),
|
||||
))
|
||||
|
||||
def test_ludicrous(self):
|
||||
self._test([['a1', 'a2', 'a3'], ['b1', 'b2']], ['c1'], [['d1', 'd2'], ['e1', 'e2', 'e3']],
|
||||
(
|
||||
('c1',),
|
||||
('b1', 'b2', 'c1'),
|
||||
('b1', 'b2', 'c1', 'd1', 'd2'),
|
||||
('a1', 'a2', 'a3', 'b1', 'b2', 'c1'),
|
||||
('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2'),
|
||||
('a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'd1', 'd2', 'e1', 'e2', 'e3'),
|
||||
))
|
||||
|
||||
def test_right_only(self):
|
||||
self._test([], [], [['a'],['b'],['c']],
|
||||
(
|
||||
(),
|
||||
('a',),
|
||||
('a', 'b'),
|
||||
('a', 'b', 'c')
|
||||
))
|
||||
|
||||
def test_have_left_options_but_required_is_empty(self):
|
||||
def fn():
|
||||
clinic.permute_optional_groups(['a'], [], [])
|
||||
self.assertRaises(AssertionError, fn)
|
||||
|
||||
|
||||
class ClinicLinearFormatTest(TestCase):
|
||||
def _test(self, input, output, **kwargs):
|
||||
computed = clinic.linear_format(input, **kwargs)
|
||||
self.assertEqual(output, computed)
|
||||
|
||||
def test_empty_strings(self):
|
||||
self._test('', '')
|
||||
|
||||
def test_solo_newline(self):
|
||||
self._test('\n', '\n')
|
||||
|
||||
def test_no_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
""", """
|
||||
abc
|
||||
""")
|
||||
|
||||
def test_empty_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
{name}
|
||||
def
|
||||
""", """
|
||||
abc
|
||||
def
|
||||
""", name='')
|
||||
|
||||
def test_single_line_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
{name}
|
||||
def
|
||||
""", """
|
||||
abc
|
||||
GARGLE
|
||||
def
|
||||
""", name='GARGLE')
|
||||
|
||||
def test_multiline_substitution(self):
|
||||
self._test("""
|
||||
abc
|
||||
{name}
|
||||
def
|
||||
""", """
|
||||
abc
|
||||
bingle
|
||||
bungle
|
||||
|
||||
def
|
||||
""", name='bingle\nbungle\n')
|
||||
|
||||
class InertParser:
|
||||
def __init__(self, clinic):
|
||||
pass
|
||||
|
||||
def parse(self, block):
|
||||
pass
|
||||
|
||||
class CopyParser:
|
||||
def __init__(self, clinic):
|
||||
pass
|
||||
|
||||
def parse(self, block):
|
||||
block.output = block.input
|
||||
|
||||
|
||||
class ClinicBlockParserTest(TestCase):
|
||||
def _test(self, input, output):
|
||||
language = clinic.CLanguage()
|
||||
|
||||
blocks = list(clinic.BlockParser(input, language))
|
||||
writer = clinic.BlockPrinter(language)
|
||||
for block in blocks:
|
||||
writer.print_block(block)
|
||||
output = writer.f.getvalue()
|
||||
assert output == input, "output != input!\n\noutput " + repr(output) + "\n\n input " + repr(input)
|
||||
|
||||
def round_trip(self, input):
|
||||
return self._test(input, input)
|
||||
|
||||
def test_round_trip_1(self):
|
||||
self.round_trip("""
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
""")
|
||||
def test_round_trip_2(self):
|
||||
self.round_trip("""
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
/*[inert]
|
||||
abc
|
||||
[inert]*/
|
||||
def
|
||||
/*[inert checksum: 7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/
|
||||
xyz
|
||||
""")
|
||||
|
||||
def _test_clinic(self, input, output):
|
||||
language = clinic.CLanguage()
|
||||
c = clinic.Clinic(language)
|
||||
c.parsers['inert'] = InertParser(c)
|
||||
c.parsers['copy'] = CopyParser(c)
|
||||
computed = c.parse(input)
|
||||
self.assertEqual(output, computed)
|
||||
|
||||
def test_clinic_1(self):
|
||||
self._test_clinic("""
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
/*[copy]
|
||||
def
|
||||
[copy]*/
|
||||
abc
|
||||
/*[copy checksum: 03cfd743661f07975fa2f1220c5194cbaff48451]*/
|
||||
xyz
|
||||
""", """
|
||||
verbatim text here
|
||||
lah dee dah
|
||||
/*[copy]
|
||||
def
|
||||
[copy]*/
|
||||
def
|
||||
/*[copy checksum: 7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/
|
||||
xyz
|
||||
""")
|
||||
|
||||
|
||||
class ClinicParserTest(TestCase):
|
||||
def test_trivial(self):
|
||||
parser = DSLParser(FakeClinic())
|
||||
block = clinic.Block("module os\nos.access")
|
||||
parser.parse(block)
|
||||
module, function = block.signatures
|
||||
self.assertEqual("access", function.name)
|
||||
self.assertEqual("os", module.name)
|
||||
|
||||
def test_ignore_line(self):
|
||||
block = self.parse("#\nmodule os\nos.access")
|
||||
module, function = block.signatures
|
||||
self.assertEqual("access", function.name)
|
||||
self.assertEqual("os", module.name)
|
||||
|
||||
def test_param(self):
|
||||
function = self.parse_function("module os\nos.access\n path: int")
|
||||
self.assertEqual("access", function.name)
|
||||
self.assertEqual(1, len(function.parameters))
|
||||
p = function.parameters['path']
|
||||
self.assertEqual('path', p.name)
|
||||
self.assertIsInstance(p.converter, clinic.int_converter)
|
||||
|
||||
def test_param_default(self):
|
||||
function = self.parse_function("module os\nos.access\n follow_symlinks: bool = True")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(True, p.default)
|
||||
|
||||
def test_param_no_docstring(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.access
|
||||
follow_symlinks: bool = True
|
||||
something_else: str""")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(2, len(function.parameters))
|
||||
self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter)
|
||||
|
||||
def disabled_test_converter_arguments(self):
|
||||
function = self.parse_function("module os\nos.access\n path: path_t(allow_fd=1)")
|
||||
p = function.parameters['path']
|
||||
self.assertEqual(1, p.converter.args['allow_fd'])
|
||||
|
||||
def test_param_docstring(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.stat as os_stat_fn -> object(doc_default='stat_result')
|
||||
|
||||
path: str
|
||||
Path to be examined""")
|
||||
p = function.parameters['path']
|
||||
self.assertEqual("Path to be examined", p.docstring)
|
||||
self.assertEqual(function.return_converter.doc_default, 'stat_result')
|
||||
|
||||
def test_function_docstring(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.stat as os_stat_fn
|
||||
|
||||
path: str
|
||||
Path to be examined
|
||||
|
||||
Perform a stat system call on the given path.""")
|
||||
self.assertEqual("""
|
||||
Perform a stat system call on the given path.
|
||||
|
||||
os.stat(path)
|
||||
path
|
||||
Path to be examined
|
||||
""".strip(), function.docstring)
|
||||
|
||||
def test_explicit_parameters_in_docstring(self):
|
||||
function = self.parse_function("""
|
||||
module foo
|
||||
foo.bar
|
||||
x: int
|
||||
Documentation for x.
|
||||
y: int
|
||||
|
||||
This is the documentation for foo.
|
||||
|
||||
Okay, we're done here.
|
||||
""")
|
||||
self.assertEqual("""
|
||||
This is the documentation for foo.
|
||||
|
||||
foo.bar(x, y)
|
||||
x
|
||||
Documentation for x.
|
||||
|
||||
Okay, we're done here.
|
||||
""".strip(), function.docstring)
|
||||
|
||||
def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.stat
|
||||
path: str
|
||||
This/used to break Clinic!
|
||||
""")
|
||||
self.assertEqual("os.stat(path)\n\nThis/used to break Clinic!", function.docstring)
|
||||
|
||||
def test_c_name(self):
|
||||
function = self.parse_function("module os\nos.stat as os_stat_fn")
|
||||
self.assertEqual("os_stat_fn", function.c_basename)
|
||||
|
||||
def test_return_converter(self):
|
||||
function = self.parse_function("module os\nos.stat -> int")
|
||||
self.assertIsInstance(function.return_converter, clinic.int_return_converter)
|
||||
|
||||
def test_star(self):
|
||||
function = self.parse_function("module os\nos.access\n *\n follow_symlinks: bool = True")
|
||||
p = function.parameters['follow_symlinks']
|
||||
self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
|
||||
self.assertEqual(0, p.group)
|
||||
|
||||
def test_group(self):
|
||||
function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n")
|
||||
p = function.parameters['ls']
|
||||
self.assertEqual(1, p.group)
|
||||
|
||||
def test_left_group(self):
|
||||
function = self.parse_function("""
|
||||
module curses
|
||||
curses.window.addch
|
||||
[
|
||||
y: int
|
||||
Y-coordinate.
|
||||
x: int
|
||||
X-coordinate.
|
||||
]
|
||||
ch: char
|
||||
Character to add.
|
||||
[
|
||||
attr: long
|
||||
Attributes for the character.
|
||||
]
|
||||
/
|
||||
""")
|
||||
for name, group in (
|
||||
('y', -1), ('x', -1),
|
||||
('ch', 0),
|
||||
('attr', 1),
|
||||
):
|
||||
p = function.parameters[name]
|
||||
self.assertEqual(p.group, group)
|
||||
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
||||
self.assertEqual(function.docstring.strip(), """
|
||||
curses.window.addch([y, x,] ch, [attr])
|
||||
y
|
||||
Y-coordinate.
|
||||
x
|
||||
X-coordinate.
|
||||
ch
|
||||
Character to add.
|
||||
attr
|
||||
Attributes for the character.
|
||||
""".strip())
|
||||
|
||||
def test_nested_groups(self):
|
||||
function = self.parse_function("""
|
||||
module curses
|
||||
curses.window.imaginary
|
||||
[
|
||||
[
|
||||
y1: int
|
||||
Y-coordinate.
|
||||
y2: int
|
||||
Y-coordinate.
|
||||
]
|
||||
x1: int
|
||||
X-coordinate.
|
||||
x2: int
|
||||
X-coordinate.
|
||||
]
|
||||
ch: char
|
||||
Character to add.
|
||||
[
|
||||
attr1: long
|
||||
Attributes for the character.
|
||||
attr2: long
|
||||
Attributes for the character.
|
||||
attr3: long
|
||||
Attributes for the character.
|
||||
[
|
||||
attr4: long
|
||||
Attributes for the character.
|
||||
attr5: long
|
||||
Attributes for the character.
|
||||
attr6: long
|
||||
Attributes for the character.
|
||||
]
|
||||
]
|
||||
/
|
||||
""")
|
||||
for name, group in (
|
||||
('y1', -2), ('y2', -2),
|
||||
('x1', -1), ('x2', -1),
|
||||
('ch', 0),
|
||||
('attr1', 1), ('attr2', 1), ('attr3', 1),
|
||||
('attr4', 2), ('attr5', 2), ('attr6', 2),
|
||||
):
|
||||
p = function.parameters[name]
|
||||
self.assertEqual(p.group, group)
|
||||
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
|
||||
|
||||
self.assertEqual(function.docstring.strip(), """
|
||||
curses.window.imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, attr6]])
|
||||
y1
|
||||
Y-coordinate.
|
||||
y2
|
||||
Y-coordinate.
|
||||
x1
|
||||
X-coordinate.
|
||||
x2
|
||||
X-coordinate.
|
||||
ch
|
||||
Character to add.
|
||||
attr1
|
||||
Attributes for the character.
|
||||
attr2
|
||||
Attributes for the character.
|
||||
attr3
|
||||
Attributes for the character.
|
||||
attr4
|
||||
Attributes for the character.
|
||||
attr5
|
||||
Attributes for the character.
|
||||
attr6
|
||||
Attributes for the character.
|
||||
""".strip())
|
||||
|
||||
def parse_function_should_fail(self, s):
|
||||
with support.captured_stdout() as stdout:
|
||||
with self.assertRaises(SystemExit):
|
||||
self.parse_function(s)
|
||||
return stdout.getvalue()
|
||||
|
||||
def test_disallowed_grouping__two_top_groups_on_left(self):
|
||||
s = self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.two_top_groups_on_left
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
[
|
||||
group2 : int
|
||||
]
|
||||
param: int
|
||||
""")
|
||||
self.assertEqual(s,
|
||||
('Error on line 0:\n'
|
||||
'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2)\n'))
|
||||
|
||||
def test_disallowed_grouping__two_top_groups_on_right(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.two_top_groups_on_right
|
||||
param: int
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
[
|
||||
group2 : int
|
||||
]
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__parameter_after_group_on_right(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.parameter_after_group_on_right
|
||||
param: int
|
||||
[
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
group2 : int
|
||||
]
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__group_after_parameter_on_left(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.group_after_parameter_on_left
|
||||
[
|
||||
group2 : int
|
||||
[
|
||||
group1 : int
|
||||
]
|
||||
]
|
||||
param: int
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__empty_group_on_left(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.empty_group
|
||||
[
|
||||
[
|
||||
]
|
||||
group2 : int
|
||||
]
|
||||
param: int
|
||||
""")
|
||||
|
||||
def test_disallowed_grouping__empty_group_on_right(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.empty_group
|
||||
param: int
|
||||
[
|
||||
[
|
||||
]
|
||||
group2 : int
|
||||
]
|
||||
""")
|
||||
|
||||
def test_no_parameters(self):
|
||||
function = self.parse_function("""
|
||||
module foo
|
||||
foo.bar
|
||||
|
||||
Docstring
|
||||
|
||||
""")
|
||||
self.assertEqual("Docstring\n\nfoo.bar()", function.docstring)
|
||||
self.assertEqual(0, len(function.parameters))
|
||||
|
||||
def test_single_star(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
*
|
||||
*
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_without_initial_parameters_or_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
*
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_without_initial_parameters_with_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
*
|
||||
Docstring here.
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_with_initial_parameters_without_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
this: int
|
||||
*
|
||||
""")
|
||||
|
||||
def test_parameters_required_after_star_with_initial_parameters_and_docstring(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
this: int
|
||||
*
|
||||
Docstring.
|
||||
""")
|
||||
|
||||
def test_single_slash(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
/
|
||||
/
|
||||
""")
|
||||
|
||||
def test_mix_star_and_slash(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
x: int
|
||||
y: int
|
||||
*
|
||||
z: int
|
||||
/
|
||||
""")
|
||||
|
||||
def test_parameters_not_permitted_after_slash_for_now(self):
|
||||
self.parse_function_should_fail("""
|
||||
module foo
|
||||
foo.bar
|
||||
/
|
||||
x: int
|
||||
""")
|
||||
|
||||
def test_function_not_at_column_0(self):
|
||||
function = self.parse_function("""
|
||||
module foo
|
||||
foo.bar
|
||||
x: int
|
||||
Nested docstring here, goeth.
|
||||
*
|
||||
y: str
|
||||
Not at column 0!
|
||||
""")
|
||||
self.assertEqual("""
|
||||
Not at column 0!
|
||||
|
||||
foo.bar(x, *, y)
|
||||
x
|
||||
Nested docstring here, goeth.
|
||||
""".strip(), function.docstring)
|
||||
|
||||
def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
|
||||
function = self.parse_function("""
|
||||
module os
|
||||
os.stat
|
||||
path: str
|
||||
This/used to break Clinic!
|
||||
""")
|
||||
self.assertEqual("This/used to break Clinic!\n\nos.stat(path)", function.docstring)
|
||||
|
||||
def test_directive(self):
|
||||
c = FakeClinic()
|
||||
parser = DSLParser(c)
|
||||
parser.flag = False
|
||||
parser.directives['setflag'] = lambda : setattr(parser, 'flag', True)
|
||||
block = clinic.Block("setflag")
|
||||
parser.parse(block)
|
||||
self.assertTrue(parser.flag)
|
||||
|
||||
def test_legacy_converters(self):
|
||||
block = self.parse('module os\nos.access\n path: "s"')
|
||||
module, function = block.signatures
|
||||
self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter)
|
||||
|
||||
def parse(self, text):
|
||||
c = FakeClinic()
|
||||
parser = DSLParser(c)
|
||||
block = clinic.Block(text)
|
||||
parser.parse(block)
|
||||
return block
|
||||
|
||||
def parse_function(self, text):
|
||||
block = self.parse(text)
|
||||
s = block.signatures
|
||||
assert len(s) == 2
|
||||
assert isinstance(s[0], clinic.Module)
|
||||
assert isinstance(s[1], clinic.Function)
|
||||
return s[1]
|
||||
|
||||
def test_scaffolding(self):
|
||||
# test repr on special values
|
||||
self.assertEqual(repr(clinic.unspecified), '<Unspecified>')
|
||||
self.assertEqual(repr(clinic.NULL), '<Null>')
|
||||
|
||||
# test that fail fails
|
||||
with support.captured_stdout() as stdout:
|
||||
with self.assertRaises(SystemExit):
|
||||
clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69)
|
||||
self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user