Add PyStructSequence_UnnamedField. Add stat_float_times.

Use integers in stat tuple, optionally floats in named fields.
This commit is contained in:
Martin v. Löwis 2002-10-16 18:27:39 +00:00
parent 5b1614d568
commit f607bdaa77
5 changed files with 151 additions and 18 deletions

View file

@ -854,9 +854,10 @@ the \ctype{stat} structure, namely:
\member{st_ctime}
(time of most recent content modification or metadata change).
\versionchanged [The time values are floats, measuring
seconds. Fractions of a second may be reported if the system
supports that]{2.3}
\versionchanged [If \function{stat_float_times} returns true, the time
values are floats, measuring seconds. Fractions of a second may be
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
also be available:
@ -899,6 +900,32 @@ Availability: Macintosh, \UNIX, Windows.
[Added access to values as attributes of the returned object]{2.2}
\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}
Perform a \cfunction{statvfs()} system call on the given path. The
return value is an object whose attributes describe the filesystem on

View file

@ -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
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}

View file

@ -19,6 +19,8 @@ typedef struct PyStructSequence_Desc {
int n_in_sequence;
} PyStructSequence_Desc;
extern char* PyStructSequence_UnnamedField;
PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
PyStructSequence_Desc *desc);

View file

@ -678,6 +678,10 @@ static PyStructSequence_Field stat_result_fields[] = {
{"st_uid", "user ID of owner"},
{"st_gid", "group ID of owner"},
{"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_mtime", "time of last modification"},
{"st_ctime", "time of last change"},
@ -694,9 +698,9 @@ static PyStructSequence_Field stat_result_fields[] = {
};
#ifdef HAVE_ST_BLKSIZE
#define ST_BLKSIZE_IDX 10
#define ST_BLKSIZE_IDX 13
#else
#define ST_BLKSIZE_IDX 9
#define ST_BLKSIZE_IDX 12
#endif
#ifdef HAVE_ST_BLOCKS
@ -749,13 +753,73 @@ static PyStructSequence_Desc statvfs_result_desc = {
static PyTypeObject StatResultType;
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
fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
{
PyObject *val;
val = PyFloat_FromDouble(sec + 1e-9*nsec);
PyStructSequence_SET_ITEM(v, index, val);
PyObject *fval,*ival;
#if SIZEOF_TIME_T > SIZEOF_LONG
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
@ -6802,6 +6866,7 @@ static PyMethodDef posix_methods[] = {
{"rename", posix_rename, METH_VARARGS, posix_rename__doc__},
{"rmdir", posix_rmdir, METH_VARARGS, posix_rmdir__doc__},
{"stat", posix_stat, METH_VARARGS, posix_stat__doc__},
{"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__},
#ifdef HAVE_SYMLINK
{"symlink", posix_symlink, METH_VARARGS, posix_symlink__doc__},
#endif /* HAVE_SYMLINK */
@ -7296,7 +7361,12 @@ INITFUNC(void)
#endif
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);
structseq_new = StatResultType.tp_new;
StatResultType.tp_new = statresult_new;
Py_INCREF((PyObject*) &StatResultType);
PyModule_AddObject(m, "stat_result", (PyObject*) &StatResultType);

View file

@ -8,6 +8,10 @@
static char visible_length_key[] = "n_sequence_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_TP(tp) PyInt_AsLong( \
PyDict_GetItemString((tp)->tp_dict, visible_length_key))
@ -332,10 +336,12 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
{
PyObject *dict;
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)
;
if (desc->fields[0].name == PyStructSequence_UnnamedField)
n_unnamed_members++;
n_members = i;
memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
@ -345,17 +351,20 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
sizeof(PyObject*)*(n_members-1);
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) {
members[i].name = desc->fields[i].name;
members[i].type = T_OBJECT;
members[i].offset = offsetof(PyStructSequence, ob_item)
for (i = k = 0; i < n_members; ++i) {
if (desc->fields[i].name == PyStructSequence_UnnamedField)
continue;
members[k].name = desc->fields[i].name;
members[k].type = T_OBJECT;
members[k].offset = offsetof(PyStructSequence, ob_item)
+ i * sizeof(PyObject*);
members[i].flags = READONLY;
members[i].doc = desc->fields[i].doc;
members[k].flags = READONLY;
members[k].doc = desc->fields[i].doc;
k++;
}
members[n_members].name = NULL;
members[k].name = NULL;
type->tp_members = members;