Skip to content

filehandle

sleap.io.format.filehandle

File object which can be passed to adaptors.

We use this since multiple file adaptors may need to open/read the file while dispatch is determining which adaptor to use, and the FileHandle allows us to keep any results from previous reads.

Classes:

Name Description
FileHandle

Reference to a file; can hold loaded data so it needn't be read twice.

FileHandle

Bases: object

Reference to a file; can hold loaded data so it needn't be read twice.

Methods:

Name Description
close

Closes the file.

open

Opens the file (if it's not already open).

Attributes:

Name Type Description
file

The raw file object.

format_id

Returns an ID from the metadata we store in some HDF5 or JSON formats.

is_hdf5

Whether file is HDF5.

is_json

Whether file is JSON.

json

The loaded JSON dictionary (for a JSON file).

text

The text from a text file.

Source code in sleap/io/format/filehandle.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
@attr.s(auto_attribs=True)
class FileHandle(object):
    """Reference to a file; can hold loaded data so it needn't be read twice."""

    filename: str
    _is_hdf5: bool = False
    _is_json: Optional[bool] = None
    _is_open: bool = False
    _file: object = None
    _text: str = None
    _json: object = None

    def __enter__(self):
        self.open()
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.close()

    def open(self):
        """Opens the file (if it's not already open)."""
        if not os.path.exists(self.filename):
            raise FileNotFoundError(f"Could not find {self.filename}")

        if self._file is None:
            try:
                self._file = h5py.File(self.filename, "r")
                self._is_hdf5 = True
            except OSError:
                # We get OSError when trying to read non-HDF5 file with h5py
                pass

        if self._file is None:
            self._file = open(self.filename, "r")
            self._is_hdf5 = False

    def close(self):
        """Closes the file."""
        if self._file is not None:
            self._file.close()

    @property
    def file(self):
        """The raw file object."""
        self.open()
        return self._file

    @property
    def text(self):
        """The text from a text file."""
        if self._text is None:
            self._text = self.file.read()
        return self._text

    @property
    def json(self):
        """The loaded JSON dictionary (for a JSON file)."""
        if self._json is None:
            self._json = json_loads(self.text)
        return self._json

    @property
    def is_json(self):
        """Whether file is JSON."""
        if self._is_json is None:
            try:
                self.json
                self._is_json = True
            except Exception:
                self._is_json = False
        return self._is_json

    @property
    def is_hdf5(self):
        """Whether file is HDF5."""
        self.open()
        return self._is_hdf5

    @property
    def format_id(self):
        """
        Returns an ID from the metadata we store in some HDF5 or JSON formats.

        This can be used if we need to distinguish multiple formats with a
        common underlying file type, e.g., HDF5-based file formats. See
        `LabelsV1Adaptor` for an example (the format id is here used to
        determine whether to convert from "gridline" to "midpixel" coordinates).
        """
        if self.is_hdf5:
            if "metadata" in self.file:
                meta_group = self.file.require_group("metadata")
                if "format_id" in meta_group.attrs:
                    return meta_group.attrs["format_id"]

        elif self.is_json:
            if "format_id" in self.json:
                return self.json["format_id"]

        return None

file property

The raw file object.

format_id property

Returns an ID from the metadata we store in some HDF5 or JSON formats.

This can be used if we need to distinguish multiple formats with a common underlying file type, e.g., HDF5-based file formats. See LabelsV1Adaptor for an example (the format id is here used to determine whether to convert from "gridline" to "midpixel" coordinates).

is_hdf5 property

Whether file is HDF5.

is_json property

Whether file is JSON.

json property

The loaded JSON dictionary (for a JSON file).

text property

The text from a text file.

close()

Closes the file.

Source code in sleap/io/format/filehandle.py
54
55
56
57
def close(self):
    """Closes the file."""
    if self._file is not None:
        self._file.close()

open()

Opens the file (if it's not already open).

Source code in sleap/io/format/filehandle.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def open(self):
    """Opens the file (if it's not already open)."""
    if not os.path.exists(self.filename):
        raise FileNotFoundError(f"Could not find {self.filename}")

    if self._file is None:
        try:
            self._file = h5py.File(self.filename, "r")
            self._is_hdf5 = True
        except OSError:
            # We get OSError when trying to read non-HDF5 file with h5py
            pass

    if self._file is None:
        self._file = open(self.filename, "r")
        self._is_hdf5 = False