[Python-Dev] PEP 410 (Decimal timestamp): the implementation is ready for a review

Victor Stinner victor.stinner at gmail.com
Thu Feb 16 13:46:18 CET 2012


> A data point on this specific use case.  The following code throws its
> assert ~90% of the time in Python 3.2.2 on a modern Linux machine (assuming
> "foo" exists and "bar" does not):
>
>   import shutil
>   import os
>   shutil.copy2("foo", "bar")
>   assert os.stat("foo").st_mtime == os.stat("bar").st_mtime

It works because Python uses float for utime() and for stat(). But
this assertion may fail if another program checks file timestamps
without lossing precision (because of float), e.g. a program written
in C that compares st_*time and st_*time_ns fields.

> I fixed this in trunk last September
> (issue 12904); os.utime now preserves all the precision that Python
> currently conveys.

Let's try in a ext4 filesystem:

$ ~/prog/python/timestamp/python
Python 3.3.0a0 (default:35d6cc531800+, Feb 16 2012, 13:32:56)
>>> import decimal, os, shutil, time
>>> open("test", "x").close()
>>> shutil.copy2("test", "test2")
>>> os.stat("test", timestamp=decimal.Decimal).st_mtime
Decimal('1329395871.874886224')
>>> os.stat("test2", timestamp=decimal.Decimal).st_mtime
Decimal('1329395871.873350282')
>>> os.stat("test2", timestamp=decimal.Decimal).st_mtime - os.stat("test", timestamp=decimal.Decimal).st_mtime
Decimal('-0.001535942')

So shutil.copy2() failed to copy the timestamp: test2 is 1 ms older than test...

Let's try with a program not written in Python: GNU make. The makefile:
---------
test2: test
        @echo "Copy test into test2"
        @~/prog/python/default/python -c 'import shutil;
shutil.copy2("test", "test2")'
test:
        @echo "Create test"
        @touch test
clean:
        rm -f test test2
---------

First try:

$ make clean
rm -f test test2
$ make
Create test
Copy test into test2
$ make
Copy test into test2

=> test2 is always older than test and so is always "regenerated".

Second try:

$ make clean
rm -f test test2
$ make
Create test
Copy test into test2
$ make
make: `test2' is up to date.

=> oh, here test2 is newer or has the exact same modification time, so
there is no need to rebuild it.

Victor


More information about the Python-Dev mailing list