mirror of
https://github.com/python/cpython.git
synced 2025-11-02 03:01:58 +00:00
Add PyStructSequence_UnnamedField. Add stat_float_times.
Use integers in stat tuple, optionally floats in named fields.
This commit is contained in:
parent
5b1614d568
commit
f607bdaa77
5 changed files with 151 additions and 18 deletions
|
|
@ -854,9 +854,10 @@ the \ctype{stat} structure, namely:
|
||||||
\member{st_ctime}
|
\member{st_ctime}
|
||||||
(time of most recent content modification or metadata change).
|
(time of most recent content modification or metadata change).
|
||||||
|
|
||||||
\versionchanged [The time values are floats, measuring
|
\versionchanged [If \function{stat_float_times} returns true, the time
|
||||||
seconds. Fractions of a second may be reported if the system
|
values are floats, measuring seconds. Fractions of a second may be
|
||||||
supports that]{2.3}
|
reported if the system supports that. On Mac OS, the times are always
|
||||||
|
floats. See \function{stat_float_times} for further discussion. ]{2.3}
|
||||||
|
|
||||||
On some Unix systems (such as Linux), the following attributes may
|
On some Unix systems (such as Linux), the following attributes may
|
||||||
also be available:
|
also be available:
|
||||||
|
|
@ -899,6 +900,32 @@ Availability: Macintosh, \UNIX, Windows.
|
||||||
[Added access to values as attributes of the returned object]{2.2}
|
[Added access to values as attributes of the returned object]{2.2}
|
||||||
\end{funcdesc}
|
\end{funcdesc}
|
||||||
|
|
||||||
|
\begin{funcdesc}{stat_float_times}{\optional{newvalue}}
|
||||||
|
Determine whether \class{stat_result} represents time stamps as float
|
||||||
|
objects. If newval is True, future calls to stat() return floats, if
|
||||||
|
it is False, future calls return ints. If newval is omitted, return
|
||||||
|
the current setting.
|
||||||
|
|
||||||
|
For compatibility with older Python versions, accessing
|
||||||
|
\class{stat_result} as a tuple always returns integers. For
|
||||||
|
compatibility with Python 2.2, accessing the time stamps by field name
|
||||||
|
also returns integers. Applications that want to determine the
|
||||||
|
fractions of a second in a time stamp can use this function to have
|
||||||
|
time stamps represented as floats. Whether they will actually observe
|
||||||
|
non-zero fractions depends on the system.
|
||||||
|
|
||||||
|
Future Python releases will change the default of this settings;
|
||||||
|
applications that cannot deal with floating point time stamps can then
|
||||||
|
use this function to turn the feature off.
|
||||||
|
|
||||||
|
It is recommended that this setting is only changed at program startup
|
||||||
|
time in the \var{__main__} module; libraries should never change this
|
||||||
|
setting. If an application uses a library that works incorrectly if
|
||||||
|
floating point time stamps are processed, this application should turn
|
||||||
|
the feature off until the library has been corrected.
|
||||||
|
|
||||||
|
\end{funcdesc}
|
||||||
|
|
||||||
\begin{funcdesc}{statvfs}{path}
|
\begin{funcdesc}{statvfs}{path}
|
||||||
Perform a \cfunction{statvfs()} system call on the given path. The
|
Perform a \cfunction{statvfs()} system call on the given path. The
|
||||||
return value is an object whose attributes describe the filesystem on
|
return value is an object whose attributes describe the filesystem on
|
||||||
|
|
|
||||||
|
|
@ -1067,6 +1067,31 @@ in \module{xml.dom.minidom} can now generate XML output in a
|
||||||
particular encoding, by specifying an optional encoding argument to
|
particular encoding, by specifying an optional encoding argument to
|
||||||
the \method{toxml()} and \method{toprettyxml()} methods of DOM nodes.
|
the \method{toxml()} and \method{toprettyxml()} methods of DOM nodes.
|
||||||
|
|
||||||
|
\item The \function{stat} family of functions can now report fractions
|
||||||
|
of a second in a time stamp. Similar to \function{time.time}, such
|
||||||
|
time stamps are represented as floats.
|
||||||
|
|
||||||
|
During testing, it was found that some applications break if time
|
||||||
|
stamps are floats. For compatibility, when using the tuple interface
|
||||||
|
of the \class{stat_result}, time stamps are represented as integers.
|
||||||
|
When using named fields (first introduced in Python 2.2), time stamps
|
||||||
|
are still represented as ints, unless \function{os.stat_float_times}
|
||||||
|
is invoked:
|
||||||
|
|
||||||
|
\begin{verbatim}
|
||||||
|
>>> os.stat_float_times(True)
|
||||||
|
>>> os.stat("/tmp").st_mtime
|
||||||
|
1034791200.6335014
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
In Python 2.4, the default will change to return floats.
|
||||||
|
|
||||||
|
Application developers should use this feature only if all their
|
||||||
|
libraries work properly when confronted with floating point time
|
||||||
|
stamps (or use the tuple API). If used, the feature should be
|
||||||
|
activated on application level, instead of trying to activate it on a
|
||||||
|
per-use basis.
|
||||||
|
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ typedef struct PyStructSequence_Desc {
|
||||||
int n_in_sequence;
|
int n_in_sequence;
|
||||||
} PyStructSequence_Desc;
|
} PyStructSequence_Desc;
|
||||||
|
|
||||||
|
extern char* PyStructSequence_UnnamedField;
|
||||||
|
|
||||||
PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
|
PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
|
||||||
PyStructSequence_Desc *desc);
|
PyStructSequence_Desc *desc);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -678,6 +678,10 @@ static PyStructSequence_Field stat_result_fields[] = {
|
||||||
{"st_uid", "user ID of owner"},
|
{"st_uid", "user ID of owner"},
|
||||||
{"st_gid", "group ID of owner"},
|
{"st_gid", "group ID of owner"},
|
||||||
{"st_size", "total size, in bytes"},
|
{"st_size", "total size, in bytes"},
|
||||||
|
/* The NULL is replaced with PyStructSequence_UnnamedField later. */
|
||||||
|
{NULL, "integer time of last access"},
|
||||||
|
{NULL, "integer time of last modification"},
|
||||||
|
{NULL, "integer time of last change"},
|
||||||
{"st_atime", "time of last access"},
|
{"st_atime", "time of last access"},
|
||||||
{"st_mtime", "time of last modification"},
|
{"st_mtime", "time of last modification"},
|
||||||
{"st_ctime", "time of last change"},
|
{"st_ctime", "time of last change"},
|
||||||
|
|
@ -694,9 +698,9 @@ static PyStructSequence_Field stat_result_fields[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_ST_BLKSIZE
|
#ifdef HAVE_ST_BLKSIZE
|
||||||
#define ST_BLKSIZE_IDX 10
|
#define ST_BLKSIZE_IDX 13
|
||||||
#else
|
#else
|
||||||
#define ST_BLKSIZE_IDX 9
|
#define ST_BLKSIZE_IDX 12
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ST_BLOCKS
|
#ifdef HAVE_ST_BLOCKS
|
||||||
|
|
@ -749,13 +753,73 @@ static PyStructSequence_Desc statvfs_result_desc = {
|
||||||
|
|
||||||
static PyTypeObject StatResultType;
|
static PyTypeObject StatResultType;
|
||||||
static PyTypeObject StatVFSResultType;
|
static PyTypeObject StatVFSResultType;
|
||||||
|
static newfunc structseq_new;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
PyStructSequence *result;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
result = (PyStructSequence*)structseq_new(type, args, kwds);
|
||||||
|
if (!result)
|
||||||
|
return NULL;
|
||||||
|
/* If we have been initialized from a tuple,
|
||||||
|
st_?time might be set to None. Initialize it
|
||||||
|
from the int slots. */
|
||||||
|
for (i = 7; i <= 9; i++) {
|
||||||
|
if (result->ob_item[i+3] == Py_None) {
|
||||||
|
Py_DECREF(Py_None);
|
||||||
|
Py_INCREF(result->ob_item[i]);
|
||||||
|
result->ob_item[i+3] = result->ob_item[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (PyObject*)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* If true, st_?time is float. */
|
||||||
|
static int _stat_float_times = 0;
|
||||||
|
|
||||||
|
PyDoc_STRVAR(stat_float_times__doc__,
|
||||||
|
"stat_float_times([newval]) -> oldval\n\n\
|
||||||
|
Determine whether os.[lf]stat represents time stamps as float objects.\n\
|
||||||
|
If newval is True, future calls to stat() return floats, if it is False,\n\
|
||||||
|
future calls return ints. \n\
|
||||||
|
If newval is omitted, return the current setting.\n");
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
stat_float_times(PyObject* self, PyObject *args)
|
||||||
|
{
|
||||||
|
int newval = -1;
|
||||||
|
if (!PyArg_ParseTuple(args, "|i:stat_float_times", &newval))
|
||||||
|
return NULL;
|
||||||
|
if (newval == -1)
|
||||||
|
/* Return old value */
|
||||||
|
return PyBool_FromLong(_stat_float_times);
|
||||||
|
_stat_float_times = newval;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
|
fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
|
||||||
{
|
{
|
||||||
PyObject *val;
|
PyObject *fval,*ival;
|
||||||
val = PyFloat_FromDouble(sec + 1e-9*nsec);
|
#if SIZEOF_TIME_T > SIZEOF_LONG
|
||||||
PyStructSequence_SET_ITEM(v, index, val);
|
ival = PyLong_FromLongLong((LONG_LONG)sec);
|
||||||
|
#else
|
||||||
|
ival = PyInt_FromLong((long)sec);
|
||||||
|
#endif
|
||||||
|
if (_stat_float_times) {
|
||||||
|
fval = PyFloat_FromDouble(sec + 1e-9*nsec);
|
||||||
|
} else {
|
||||||
|
fval = ival;
|
||||||
|
Py_INCREF(fval);
|
||||||
|
}
|
||||||
|
PyStructSequence_SET_ITEM(v, index, ival);
|
||||||
|
PyStructSequence_SET_ITEM(v, index+3, fval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pack a system stat C structure into the Python stat tuple
|
/* pack a system stat C structure into the Python stat tuple
|
||||||
|
|
@ -6802,6 +6866,7 @@ static PyMethodDef posix_methods[] = {
|
||||||
{"rename", posix_rename, METH_VARARGS, posix_rename__doc__},
|
{"rename", posix_rename, METH_VARARGS, posix_rename__doc__},
|
||||||
{"rmdir", posix_rmdir, METH_VARARGS, posix_rmdir__doc__},
|
{"rmdir", posix_rmdir, METH_VARARGS, posix_rmdir__doc__},
|
||||||
{"stat", posix_stat, METH_VARARGS, posix_stat__doc__},
|
{"stat", posix_stat, METH_VARARGS, posix_stat__doc__},
|
||||||
|
{"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__},
|
||||||
#ifdef HAVE_SYMLINK
|
#ifdef HAVE_SYMLINK
|
||||||
{"symlink", posix_symlink, METH_VARARGS, posix_symlink__doc__},
|
{"symlink", posix_symlink, METH_VARARGS, posix_symlink__doc__},
|
||||||
#endif /* HAVE_SYMLINK */
|
#endif /* HAVE_SYMLINK */
|
||||||
|
|
@ -7296,7 +7361,12 @@ INITFUNC(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
stat_result_desc.name = MODNAME ".stat_result";
|
stat_result_desc.name = MODNAME ".stat_result";
|
||||||
|
stat_result_desc.fields[7].name = PyStructSequence_UnnamedField;
|
||||||
|
stat_result_desc.fields[8].name = PyStructSequence_UnnamedField;
|
||||||
|
stat_result_desc.fields[9].name = PyStructSequence_UnnamedField;
|
||||||
PyStructSequence_InitType(&StatResultType, &stat_result_desc);
|
PyStructSequence_InitType(&StatResultType, &stat_result_desc);
|
||||||
|
structseq_new = StatResultType.tp_new;
|
||||||
|
StatResultType.tp_new = statresult_new;
|
||||||
Py_INCREF((PyObject*) &StatResultType);
|
Py_INCREF((PyObject*) &StatResultType);
|
||||||
PyModule_AddObject(m, "stat_result", (PyObject*) &StatResultType);
|
PyModule_AddObject(m, "stat_result", (PyObject*) &StatResultType);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@
|
||||||
static char visible_length_key[] = "n_sequence_fields";
|
static char visible_length_key[] = "n_sequence_fields";
|
||||||
static char real_length_key[] = "n_fields";
|
static char real_length_key[] = "n_fields";
|
||||||
|
|
||||||
|
/* Fields with this name have only a field index, not a field name.
|
||||||
|
They are only allowed for indices < n_visible_fields. */
|
||||||
|
char *PyStructSequence_UnnamedField = "unnamed field";
|
||||||
|
|
||||||
#define VISIBLE_SIZE(op) ((op)->ob_size)
|
#define VISIBLE_SIZE(op) ((op)->ob_size)
|
||||||
#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \
|
#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \
|
||||||
PyDict_GetItemString((tp)->tp_dict, visible_length_key))
|
PyDict_GetItemString((tp)->tp_dict, visible_length_key))
|
||||||
|
|
@ -332,10 +336,12 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
|
||||||
{
|
{
|
||||||
PyObject *dict;
|
PyObject *dict;
|
||||||
PyMemberDef* members;
|
PyMemberDef* members;
|
||||||
int n_members, i;
|
int n_members, n_unnamed_members, i, k;
|
||||||
|
|
||||||
|
n_unnamed_members = 0;
|
||||||
for (i = 0; desc->fields[i].name != NULL; ++i)
|
for (i = 0; desc->fields[i].name != NULL; ++i)
|
||||||
;
|
if (desc->fields[0].name == PyStructSequence_UnnamedField)
|
||||||
|
n_unnamed_members++;
|
||||||
n_members = i;
|
n_members = i;
|
||||||
|
|
||||||
memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
|
memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
|
||||||
|
|
@ -345,17 +351,20 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
|
||||||
sizeof(PyObject*)*(n_members-1);
|
sizeof(PyObject*)*(n_members-1);
|
||||||
type->tp_itemsize = 0;
|
type->tp_itemsize = 0;
|
||||||
|
|
||||||
members = PyMem_NEW(PyMemberDef, n_members+1);
|
members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
|
||||||
|
|
||||||
for (i = 0; i < n_members; ++i) {
|
for (i = k = 0; i < n_members; ++i) {
|
||||||
members[i].name = desc->fields[i].name;
|
if (desc->fields[i].name == PyStructSequence_UnnamedField)
|
||||||
members[i].type = T_OBJECT;
|
continue;
|
||||||
members[i].offset = offsetof(PyStructSequence, ob_item)
|
members[k].name = desc->fields[i].name;
|
||||||
|
members[k].type = T_OBJECT;
|
||||||
|
members[k].offset = offsetof(PyStructSequence, ob_item)
|
||||||
+ i * sizeof(PyObject*);
|
+ i * sizeof(PyObject*);
|
||||||
members[i].flags = READONLY;
|
members[k].flags = READONLY;
|
||||||
members[i].doc = desc->fields[i].doc;
|
members[k].doc = desc->fields[i].doc;
|
||||||
|
k++;
|
||||||
}
|
}
|
||||||
members[n_members].name = NULL;
|
members[k].name = NULL;
|
||||||
|
|
||||||
type->tp_members = members;
|
type->tp_members = members;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue