From 65cbe0ef684fac8b59a38b31395e2a502ad606df Mon Sep 17 00:00:00 2001 From: Thomas H Date: Fri, 23 Aug 2024 14:09:05 -0400 Subject: [PATCH] Add `st_birthtime` as standard field (#254) * Add .vscode to .gitignore * Add tests for stat time values * Add tests for birthtime * Move birthtime implementation * upath._stat: fix linter error --------- Co-authored-by: Thomas H Co-authored-by: Andreas Poehlmann --- .gitignore | 3 +++ upath/_stat.py | 36 ++++++++++++++++++++---------------- upath/tests/test_stat.py | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index e3312579..059c6188 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,6 @@ cython_debug/ # setuptools_scm upath/_version.py + +# vscode workspace settings +.vscode/ diff --git a/upath/_stat.py b/upath/_stat.py index f2cbece7..5a4f0b1f 100644 --- a/upath/_stat.py +++ b/upath/_stat.py @@ -281,6 +281,26 @@ def st_ctime(self) -> int | float: pass return self._seq[9] + @property + def st_birthtime(self) -> int | float: + """time of creation""" + for key in [ + "birthtime", + "created", + "creation_time", + "timeCreated", + "created_at", + ]: + try: + raw_value = self._info[key] + except KeyError: + continue + try: + return _convert_value_to_timestamp(raw_value) + except (TypeError, ValueError): + pass + raise AttributeError("birthtime") + # --- extra fields ------------------------------------------------ def __getattr__(self, item): @@ -288,22 +308,6 @@ def __getattr__(self, item): return 0 # fallback default value raise AttributeError(item) - if "st_birthtime" in _fields_extra: - - @property - def st_birthtime(self) -> int | float: - """time of creation""" - for key in ["created", "creation_time", "timeCreated", "created_at"]: - try: - raw_value = self._info[key] - except KeyError: - continue - try: - return _convert_value_to_timestamp(raw_value) - except (TypeError, ValueError): - pass - return 0 - # --- os.stat_result tuple interface ------------------------------ def __len__(self) -> int: diff --git a/upath/tests/test_stat.py b/upath/tests/test_stat.py index 66d9668c..4922ae1e 100644 --- a/upath/tests/test_stat.py +++ b/upath/tests/test_stat.py @@ -25,15 +25,45 @@ def test_stat_as_info(pth_file): def test_stat_atime(pth_file): - assert isinstance(pth_file.stat().st_atime, (float, int)) + atime = pth_file.stat().st_atime + assert isinstance(atime, (float, int)) + + +@pytest.mark.xfail(reason="fsspec does not return 'atime'") +def test_stat_atime_value(pth_file): + atime = pth_file.stat().st_atime + assert atime > 0 def test_stat_mtime(pth_file): - assert isinstance(pth_file.stat().st_mtime, (float, int)) + mtime = pth_file.stat().st_mtime + assert isinstance(mtime, (float, int)) + + +def test_stat_mtime_value(pth_file): + mtime = pth_file.stat().st_mtime + assert mtime > 0 def test_stat_ctime(pth_file): - assert isinstance(pth_file.stat().st_ctime, (float, int)) + ctime = pth_file.stat().st_ctime + assert isinstance(ctime, (float, int)) + + +@pytest.mark.xfail(reason="fsspec returns 'created' but not 'ctime'") +def test_stat_ctime_value(pth_file): + ctime = pth_file.stat().st_ctime + assert ctime > 0 + + +def test_stat_birthtime(pth_file): + birthtime = pth_file.stat().st_birthtime + assert isinstance(birthtime, (float, int)) + + +def test_stat_birthtime_value(pth_file): + birthtime = pth_file.stat().st_birthtime + assert birthtime > 0 def test_stat_seq_interface(pth_file):