Repository: dask/fastparquet

Issue:
``statistics`` does not work on a ParquetFile subset?
**Describe the issue**:

**Minimal Complete Verifiable Example**:

```python
import pandas as pd
import fastparquet as fp

fp.write(filename="small_df", data=pd.DataFrame({'a':[1,2,3]}), row_group_offsets=[0,2], file_scheme="hive")
pf = fp.ParquetFile("small_df")

# Works
pf.statistics
{'min': {'a': [1, 3]},
 'max': {'a': [2, 3]},
 'null_count': {'a': [0, 0]},
 'distinct_count': {'a': [None, None]}}

# Does not work
pf[-1].statistics
AttributeError: 'ParquetFile' object has no attribute '_statistics'

```

Selecting row groups should still result in a ``ParquetFile`` and ``statistics`` should work?

**Environment**:

- Python version: 3.10
- Operating System: Ubutnu
- Install method (conda, pip, source): conda


Discussion:
yohplala: Hi  @martindurant 
I checked all failing environments, it is systematically related to a trouble with the setting of the conda env. and tests are actually not run.

```
C:\Users\runneradmin\micromamba-bin\micromamba.exe shell deinit -s bash -p C:\Users\runneradmin\micromamba-root -y --log-level warning
  The following argument was not expected: -p
  Run with --help for more information.
  D:\a\_actions\mamba-org\provision-with-micromamba\main\dist\post\index.js:62[5](https://github.com/dask/fastparquet/actions/runs/11574863592/job/32220088198?pr=940#step:9:5)85
      throw Error(`Failed to execute ${JSON.stringify(args)}: ${error}`)
            ^
  
  Error: Failed to execute ["C:\\Users\\runneradmin\\micromamba-bin\\micromamba",["shell","deinit","-s","bash","-p","C:\\Users\\runneradmin\\micromamba-root","-y","--log-level","warning"]]: Error: The process 'C:\Users\runneradmin\micromamba-bin\micromamba.exe' failed with exit code 10[9](https://github.com/dask/fastparquet/actions/runs/11574863592/job/32220088198?pr=940#step:9:9)
```
yohplala: @martindurant , I am not super expert with the definition of cached properties. Don't hesitate to ask for an alternative fix if this one is not appropriate (I would do with some directions)

Patch:
diff --git a/fastparquet/api.py b/fastparquet/api.py
index c54e5eb..3f6f781 100644
--- a/fastparquet/api.py
+++ b/fastparquet/api.py
@@ -260,7 +260,7 @@ class ParquetFile(object):
 
     @property
     def statistics(self):
-        if self._statistics is None:
+        if not hasattr(self, '_statistics') or self._statistics is None:
             self._statistics = statistics(self)
         return self._statistics
 


Test patch:
diff --git a/fastparquet/test/test_api.py b/fastparquet/test/test_api.py
index a7f824e..6ffdce5 100644
--- a/fastparquet/test/test_api.py
+++ b/fastparquet/test/test_api.py
@@ -44,14 +44,23 @@ def test_statistics(tempdir):
     p = ParquetFile(fn)
 
     s = statistics(p)
-    expected = {'distinct_count': {'x': [None, None],
+    expected1 = {'distinct_count': {'x': [None, None],
                                    'y': [None, None],
                                    'z': [None, None]},
                 'max': {'x': [2, 3], 'y': [2.0, 1.0], 'z': ['b', 'c']},
                 'min': {'x': [1, 3], 'y': [1.0, 1.0], 'z': ['a', 'c']},
                 'null_count': {'x': [0, 0], 'y': [0, 0], 'z': [0, 0]}}
 
-    assert s == expected
+    assert s == expected1
+
+    expected2 = {'distinct_count': {'x': [None],
+                                   'y': [None],
+                                   'z': [None]},
+                'max': {'x': [3], 'y': [1.0], 'z': ['c']},
+                'min': {'x': [3], 'y': [1.0], 'z': ['c']},
+                'null_count': {'x': [0], 'y': [0], 'z': [0]}}
+
+    assert p[-1].statistics == expected2
 
 
 def test_logical_types(tempdir):