Skip to content

Filesystem

Some PalmSens devices, like the EmStat 4, EmStat Pico, Sensit Wearable, and Nexus) have an internal filesystem where they can store measurements (.dmeas files), and other data, e.g. generated by MethodSCRIPT. PyPalmSens provides a file-system-like interface to browse, read, write, and delete files on the connected instrument through pypalmsens.DeviceFileSystem. Asynchronous workflows are supported via pypalmsens.DeviceFileSystemAsync.

Example:

>>> import pypalmsens as ps

>>> with ps.connect() as manager:
...     fs = ps.DeviceFileSystem(manager)
...     print(fs.listdir())
[DevicePath('Measurements/17-07-2026/LSV-10-00-25-0.dmeas'),
 DevicePath('Measurements/17-07-2026/LSV-10-00-28-1.dmeas'),
 DevicePath('Measurements/16-07-2026/CV-14-46-50-2.dmeas')]

For more information how to use these classes, see the documentation here.

Classes:

pypalmsens.DevicePath

A path object representing a file or directory on the device.

Subclasses pathlib.PurePath to provide POSIX-style path semantics for PalmSens device filesystem paths.

pypalmsens.DeviceFileSystem

Provide a file-system-like interface to a PalmSens device.

Allows browsing, reading, writing, and deleting files on the connected instrument as if they were entries in a local directory tree.

Note that if not used as a context manager, the manager must have an active connection with the device.

Parameters:

  • instrument_or_manager

    (Instrument | InstrumentManager) –

    An instrument instance or an existing InstrumentManager. If an instrument is passed, a new manager will be created.

Methods:

  • __truediv__

    Join a path component to the root directory.

  • delete_all_files

    Delete all files on the device.

  • exists

    Check whether a path exists on the device.

  • free

    Return free space on filesystem.

  • iterdir

    Iterate over entries in a device directory.

  • listdir

    List all entries in a device directory.

  • load_measurement

    Load measurement from path on device.

  • read_text

    Read the content of a file as text.

  • remove

    Remove a file from the device.

  • size

    Return total size of filesystem.

  • size_of

    Get the size of a file.

  • timestamp_of

    Get the modification timestamp of a file.

  • walk

    Generate file names by walking the directory tree starting from a device directory.

Attributes:

Source code in src/pypalmsens/_instruments/filesystem.py
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def __init__(self, instrument_or_manager: Instrument | InstrumentManager):
    """Initialize the filesystem.

    Note that if not used as a context manager,
    the manager must have an active connection with the device.

    Parameters
    ----------
    instrument_or_manager : Instrument | InstrumentManager
        An instrument instance or an existing `InstrumentManager`.
        If an instrument is passed, a new manager will be created.
    """
    self.manager: InstrumentManager

    if isinstance(instrument_or_manager, Instrument):
        self.manager = InstrumentManager(instrument_or_manager)
    else:
        self.manager = instrument_or_manager

    if not self.manager.capabilities.supports_storage:
        raise ValueError(
            f'{self.manager.instrument.name!r} does not have or support internal storage.'
        )

root property

root: DevicePath

Return path of root directory.

Returns:

__truediv__

__truediv__(path_str: str) -> DevicePath

Join a path component to the root directory.

Source code in src/pypalmsens/_instruments/filesystem.py
115
116
117
def __truediv__(self, path_str: str) -> DevicePath:
    """Join a path component to the root directory."""
    return self.root / path_str

delete_all_files

delete_all_files(confirm: bool = False) -> None

Delete all files on the device.

Parameters:

  • confirm

    (bool, default: False ) –

    If True, clear all files on the device. Default is False. This acts as a sentinel to avoid accidental deletes in interactive REPL or Jupyter environments.

Source code in src/pypalmsens/_instruments/filesystem.py
222
223
224
225
226
227
228
229
230
231
232
233
234
def delete_all_files(self, confirm: bool = False) -> None:
    """Delete all files on the device.

    Parameters
    ----------
    confirm : bool, optional
        If True, clear all files on the device. Default is False.
        This acts as a sentinel to avoid accidental deletes in
        interactive REPL or Jupyter environments.
    """
    if confirm:
        with self.manager._lock():
            self._client_connection.ClearDeviceFiles()

exists

exists(path: str | DevicePath) -> bool

Check whether a path exists on the device.

Parameters:

  • path

    (str | DevicePath) –

    The file or directory path to check.

Returns:

  • bool

    True if the path exists, False otherwise.

Source code in src/pypalmsens/_instruments/filesystem.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def exists(self, path: str | DevicePath) -> bool:
    """Check whether a path exists on the device.

    Parameters
    ----------
    path : str | DevicePath
        The file or directory path to check.

    Returns
    -------
    bool
        True if the path exists, False otherwise.
    """
    if not isinstance(path, DevicePath):
        path = DevicePath(path)

    if str(path) == '':  # root always exists
        return True

    for entry in self.iterdir(path.parent):
        if entry == path:  # check if direct match
            return True

        if entry.is_relative_to(path):  # check for subdirectory match
            return True

    return False

free

free() -> int

Return free space on filesystem.

Returns:

  • int

    Free space in bytes (1 kB = 1024 bytes).

Source code in src/pypalmsens/_instruments/filesystem.py
236
237
238
239
240
241
242
243
244
245
def free(self) -> int:
    """Return free space on filesystem.

    Returns
    -------
    int
        Free space in bytes (1 kB = 1024 bytes).
    """
    with self.manager._lock():
        return self._client_connection.GetDeviceFree()

iterdir

iterdir(directory: DevicePath | str | None = None) -> Iterator[DevicePath]

Iterate over entries in a device directory.

Note that some devices like EmStat4 return all subdirectories and files at once.

Parameters:

  • directory

    (DevicePath | str | None, default: None ) –

    The directory to iterate. Defaults to the root directory.

Yields:

  • paths ( Iterator[DevicePath] ) –

    Path objects for each entry in the directory.

Source code in src/pypalmsens/_instruments/filesystem.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
def iterdir(self, directory: DevicePath | str | None = None) -> Iterator[DevicePath]:
    """Iterate over entries in a device directory.

    Note that some devices like EmStat4 return all subdirectories and files
    at once.

    Parameters
    ----------
    directory : DevicePath | str | None, optional
        The directory to iterate. Defaults to the root directory.

    Yields
    ------
    paths: Iterator[DevicePath]
        Path objects for each entry in the directory.
    """
    paths = self._get_device_files(directory=directory)

    for path in paths:
        yield DevicePath(path.Dir, path.Name)

listdir

listdir(directory: DevicePath | str | None = None) -> list[DevicePath]

List all entries in a device directory.

Note that some devices like EmStat4 return all subdirectories and files at once.

Parameters:

  • directory

    (DevicePath | str | None, default: None ) –

    The directory to iterate. Defaults to the root directory.

Yields:

  • paths ( Iterator[DevicePath] ) –

    Path objects for each entry in the directory.

Source code in src/pypalmsens/_instruments/filesystem.py
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
def listdir(self, directory: DevicePath | str | None = None) -> list[DevicePath]:
    """List all entries in a device directory.

    Note that some devices like EmStat4 return all subdirectories and files
    at once.

    Parameters
    ----------
    directory : DevicePath | str | None, optional
        The directory to iterate. Defaults to the root directory.

    Yields
    ------
    paths: Iterator[DevicePath]
        Path objects for each entry in the directory.
    """
    return list(self.iterdir(directory=directory))

load_measurement

load_measurement(path: str | DevicePath) -> Measurement

Load measurement from path on device.

Parameters:

Returns:

Source code in src/pypalmsens/_instruments/filesystem.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def load_measurement(self, path: str | DevicePath) -> Measurement:
    """Load measurement from path on device.

    Parameters
    ----------
    path : str | DevicePath
        The file path to load.

    Returns
    -------
    Measurement
        Measurement data.
    """
    f = self._get_device_file(path)

    psmeasurement = self._client_connection.LoadDeviceFile(f)

    return Measurement(psmeasurement=psmeasurement)

read_text

read_text(path: DevicePath) -> str

Read the content of a file as text.

Parameters:

Returns:

  • str

    File contents as a string.

Source code in src/pypalmsens/_instruments/filesystem.py
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
def read_text(self, path: DevicePath) -> str:
    """Read the content of a file as text.

    Parameters
    ----------
    path : DevicePath
        The file path.

    Returns
    -------
    str
        File contents as a string.
    """
    f = self._get_device_file(path)

    return f.Content

remove

remove(path: str | DevicePath) -> None

Remove a file from the device.

Parameters:

Source code in src/pypalmsens/_instruments/filesystem.py
208
209
210
211
212
213
214
215
216
217
218
219
220
def remove(self, path: str | DevicePath) -> None:
    """Remove a file from the device.

    Parameters
    ----------
    path : str | DevicePath
        The file path to remove.
    """
    if isinstance(path, str):
        path = DevicePath(path)

    with self.manager._lock():
        self._client_connection.DeleteDeviceFile(str(path))

size

size() -> int

Return total size of filesystem.

Returns:

  • int

    Total size in bytes.

Source code in src/pypalmsens/_instruments/filesystem.py
247
248
249
250
251
252
253
254
255
256
def size(self) -> int:
    """Return total size of filesystem.

    Returns
    -------
    int
        Total size in bytes.
    """
    with self.manager._lock():
        return self._client_connection.GetDeviceSize()

size_of

size_of(path: str | DevicePath) -> int

Get the size of a file.

Parameters:

Returns:

  • int

    File size in bytes (1 kB = 1024 bytes).

Source code in src/pypalmsens/_instruments/filesystem.py
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
def size_of(self, path: str | DevicePath) -> int:
    """Get the size of a file.

    Parameters
    ----------
    path : str | DevicePath
        The file path.

    Returns
    -------
    int
        File size in bytes (1 kB = 1024 bytes).
    """
    f = self._get_device_file(path)

    return f.Size

timestamp_of

timestamp_of(path: str | DevicePath) -> str

Get the modification timestamp of a file.

Parameters:

Returns:

  • str

    Timestamp in ISO format.

Source code in src/pypalmsens/_instruments/filesystem.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
def timestamp_of(self, path: str | DevicePath) -> str:
    """Get the modification timestamp of a file.

    Parameters
    ----------
    path : str | DevicePath
        The file path.

    Returns
    -------
    str
        Timestamp in ISO format.
    """
    f = self._get_device_file(path)

    return f.Timestamp.ToString('s', System.Globalization.CultureInfo.InvariantCulture)

walk

walk(directory: DevicePath | str | None = None) -> Iterator[DevicePath]

Generate file names by walking the directory tree starting from a device directory.

Parameters:

  • directory

    (DevicePath | str | None, default: None ) –

    The directory to walk through. Defaults to the root directory.

Yields:

  • paths ( Iterator[DevicePath] ) –

    Path objects for each entry in the directory.

Source code in src/pypalmsens/_instruments/filesystem.py
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
def walk(self, directory: DevicePath | str | None = None) -> Iterator[DevicePath]:
    """Generate file names by walking the directory tree starting from a device directory.

    Parameters
    ----------
    directory : DevicePath | str | None, optional
        The directory to walk through. Defaults to the root directory.

    Yields
    ------
    paths: Iterator[DevicePath]
        Path objects for each entry in the directory.
    """
    paths = self._get_device_files(directory=directory)

    for path in paths:
        df = DevicePath(path.Dir, path.Name)

        if str(path.Type) == 'Folder':
            yield from self.walk(str(df))
        else:
            yield df

pypalmsens.DeviceFileSystemAsync

Provide a file-system-like interface to a PalmSens device.

Allows browsing, reading, writing, and deleting files on the connected instrument as if they were entries in a local directory tree.

Note that if not used as a context manager, the manager must have an active connection with the device.

Parameters:

  • instrument_or_manager

    (Instrument | InstrumentManagerAsync) –

    An instrument instance or an existing InstrumentManagerAsync. If an instrument is passed, a new manager will be created.

Methods:

  • __truediv__

    Join a path component to the root directory.

  • delete_all_files

    Delete all files on the device.

  • exists

    Check whether a path exists on the device.

  • free

    Return free space on filesystem.

  • iterdir

    Iterate over entries in a device directory.

  • listdir

    List all entries in a device directory.

  • load_measurement

    Load measurement from path on device.

  • read_text

    Read the content of a file as text.

  • remove

    Remove a file from the device.

  • size

    Return total size of filesystem.

  • size_of

    Get the size of a file.

  • timestamp_of

    Get the modification timestamp of a file.

  • walk

    Generate file names by walking the directory tree starting from a device directory.

Attributes:

Source code in src/pypalmsens/_instruments/filesystem_async.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def __init__(self, instrument_or_manager: Instrument | InstrumentManagerAsync):
    """Initialize the filesystem.

    Note that if not used as a context manager,
    the manager must have an active connection with the device.

    Parameters
    ----------
    instrument_or_manager : Instrument | InstrumentManagerAsync
        An instrument instance or an existing `InstrumentManagerAsync`.
        If an instrument is passed, a new manager will be created.
    """
    self.manager: InstrumentManagerAsync

    if isinstance(instrument_or_manager, Instrument):
        self.manager = InstrumentManagerAsync(instrument_or_manager)
    else:
        self.manager = instrument_or_manager

    if not self.manager.capabilities.supports_storage:
        raise ValueError(
            f'{self.manager.instrument.name!r} does not have or support internal storage.'
        )

root property

root: DevicePath

Return path of root directory.

Returns:

__truediv__

__truediv__(path_str: str) -> DevicePath

Join a path component to the root directory.

Source code in src/pypalmsens/_instruments/filesystem_async.py
61
62
63
def __truediv__(self, path_str: str) -> DevicePath:
    """Join a path component to the root directory."""
    return self.root / path_str

delete_all_files async

delete_all_files(confirm: bool = False) -> None

Delete all files on the device.

Parameters:

  • confirm

    (bool, default: False ) –

    If True, clear all files on the device. Default is False. This acts as a sentinel to avoid accidental deletes in interactive REPL or Jupyter environments.

Source code in src/pypalmsens/_instruments/filesystem_async.py
181
182
183
184
185
186
187
188
189
190
191
192
193
async def delete_all_files(self, confirm: bool = False) -> None:
    """Delete all files on the device.

    Parameters
    ----------
    confirm : bool, optional
        If True, clear all files on the device. Default is False.
        This acts as a sentinel to avoid accidental deletes in
        interactive REPL or Jupyter environments.
    """
    if confirm:
        async with self.manager._lock():
            await create_future(self._client_connection.ClearDeviceFilesAsync())

exists async

exists(path: str | DevicePath) -> bool

Check whether a path exists on the device.

Parameters:

  • path

    (str | DevicePath) –

    The file or directory path to check.

Returns:

  • bool

    True if the path exists, False otherwise.

Source code in src/pypalmsens/_instruments/filesystem_async.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
async def exists(self, path: str | DevicePath) -> bool:
    """Check whether a path exists on the device.

    Parameters
    ----------
    path : str | DevicePath
        The file or directory path to check.

    Returns
    -------
    bool
        True if the path exists, False otherwise.
    """
    if not isinstance(path, DevicePath):
        path = DevicePath(path)

    if str(path) == '':  # root always exists
        return True

    async for entry in self.iterdir(path.parent):
        if entry == path:  # check if direct match
            return True

        if entry.is_relative_to(path):  # check for subdirectory match
            return True

    return False

free async

free() -> int

Return free space on filesystem.

Returns:

  • int

    Free space in kB (1 kB = 1024 bytes).

Source code in src/pypalmsens/_instruments/filesystem_async.py
195
196
197
198
199
200
201
202
203
204
async def free(self) -> int:
    """Return free space on filesystem.

    Returns
    -------
    int
        Free space in kB (1 kB = 1024 bytes).
    """
    async with self.manager._lock():
        return await create_future(self._client_connection.GetDeviceFreeAsync())

iterdir async

iterdir(directory: DevicePath | str | None = None) -> AsyncIterator[DevicePath]

Iterate over entries in a device directory.

Note that some devices like EmStat4 return all subdirectories and files at once.

Parameters:

  • directory

    (DevicePath | str | None, default: None ) –

    The directory to iterate. Defaults to the root directory.

Yields:

  • paths ( Iterator[DevicePath] ) –

    Path objects for each entry in the directory.

Source code in src/pypalmsens/_instruments/filesystem_async.py
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
async def iterdir(
    self, directory: DevicePath | str | None = None
) -> AsyncIterator[DevicePath]:
    """Iterate over entries in a device directory.

    Note that some devices like EmStat4 return all subdirectories and files
    at once.

    Parameters
    ----------
    directory : DevicePath | str | None, optional
        The directory to iterate. Defaults to the root directory.

    Yields
    ------
    paths: Iterator[DevicePath]
        Path objects for each entry in the directory.
    """
    paths = await self._get_device_files(directory=directory)

    for path in paths:
        yield DevicePath(path.Dir, path.Name)

listdir async

listdir(directory: DevicePath | str | None = None) -> list[DevicePath]

List all entries in a device directory.

Note that some devices like EmStat4 return all subdirectories and files at once.

Parameters:

  • directory

    (DevicePath | str | None, default: None ) –

    The directory to iterate. Defaults to the root directory.

Yields:

  • paths ( Iterator[DevicePath] ) –

    Path objects for each entry in the directory.

Source code in src/pypalmsens/_instruments/filesystem_async.py
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
async def listdir(self, directory: DevicePath | str | None = None) -> list[DevicePath]:
    """List all entries in a device directory.

    Note that some devices like EmStat4 return all subdirectories and files
    at once.

    Parameters
    ----------
    directory : DevicePath | str | None, optional
        The directory to iterate. Defaults to the root directory.

    Yields
    ------
    paths: Iterator[DevicePath]
        Path objects for each entry in the directory.
    """
    return [_ async for _ in self.iterdir(directory=directory)]

load_measurement async

load_measurement(path: str | DevicePath) -> Measurement

Load measurement from path on device.

Parameters:

Returns:

Source code in src/pypalmsens/_instruments/filesystem_async.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
async def load_measurement(self, path: str | DevicePath) -> Measurement:
    """Load measurement from path on device.

    Parameters
    ----------
    path : str | DevicePath
        The file path to load.

    Returns
    -------
    Measurement
        Measurement data.
    """
    f = await self._get_device_file(path)

    async with self.manager._lock():
        psmeasurement: PalmSens.Measurement = await create_future(
            self._client_connection.LoadDeviceFileAsync(f)
        )

    return Measurement(psmeasurement=psmeasurement)

read_text async

read_text(path: DevicePath) -> str

Read the content of a file as text.

Parameters:

Returns:

  • str

    File contents as a string.

Source code in src/pypalmsens/_instruments/filesystem_async.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
async def read_text(self, path: DevicePath) -> str:
    """Read the content of a file as text.

    Parameters
    ----------
    path : DevicePath
        The file path.

    Returns
    -------
    str
        File contents as a string.
    """
    f = await self._get_device_file(path)

    return f.Content

remove async

remove(path: str | DevicePath) -> None

Remove a file from the device.

Parameters:

Source code in src/pypalmsens/_instruments/filesystem_async.py
167
168
169
170
171
172
173
174
175
176
177
178
179
async def remove(self, path: str | DevicePath) -> None:
    """Remove a file from the device.

    Parameters
    ----------
    path : str | DevicePath
        The file path to remove.
    """
    if isinstance(path, str):
        path = DevicePath(path)

    async with self.manager._lock():
        await create_future(self._client_connection.DeleteDeviceFileAsync(str(path)))

size async

size() -> int

Return total size of filesystem.

Returns:

  • int

    Total size in kB (1 kB = 1024 bytes).

Source code in src/pypalmsens/_instruments/filesystem_async.py
206
207
208
209
210
211
212
213
214
215
async def size(self) -> int:
    """Return total size of filesystem.

    Returns
    -------
    int
        Total size in kB (1 kB = 1024 bytes).
    """
    async with self.manager._lock():
        return await create_future(self._client_connection.GetDeviceSizeAsync())

size_of async

size_of(path: str | DevicePath) -> int

Get the size of a file.

Parameters:

Returns:

  • int

    File size in bytes.

Source code in src/pypalmsens/_instruments/filesystem_async.py
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
async def size_of(self, path: str | DevicePath) -> int:
    """Get the size of a file.

    Parameters
    ----------
    path : str | DevicePath
        The file path.

    Returns
    -------
    int
        File size in bytes.
    """
    f = await self._get_device_file(path)

    return f.Size

timestamp_of async

timestamp_of(path: str | DevicePath) -> str

Get the modification timestamp of a file.

Parameters:

Returns:

  • str

    Timestamp in ISO format.

Source code in src/pypalmsens/_instruments/filesystem_async.py
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
async def timestamp_of(self, path: str | DevicePath) -> str:
    """Get the modification timestamp of a file.

    Parameters
    ----------
    path : str | DevicePath
        The file path.

    Returns
    -------
    str
        Timestamp in ISO format.
    """
    f = await self._get_device_file(path)

    return f.Timestamp.ToString('s', System.Globalization.CultureInfo.InvariantCulture)

walk async

walk(directory: DevicePath | str | None = None) -> AsyncIterator[DevicePath]

Generate file names by walking the directory tree starting from a device directory.

Parameters:

  • directory

    (DevicePath | str | None, default: None ) –

    The directory to walk through. Defaults to the root directory.

Yields:

  • paths ( Iterator[DevicePath] ) –

    Path objects for each entry in the directory.

Source code in src/pypalmsens/_instruments/filesystem_async.py
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
async def walk(
    self, directory: DevicePath | str | None = None
) -> AsyncIterator[DevicePath]:
    """Generate file names by walking the directory tree starting from a device directory.

    Parameters
    ----------
    directory : DevicePath | str | None, optional
        The directory to walk through. Defaults to the root directory.

    Yields
    ------
    paths: Iterator[DevicePath]
        Path objects for each entry in the directory.
    """
    paths = await self._get_device_files(directory=directory)

    for path in paths:
        df = DevicePath(path.Dir, path.Name)

        if str(path.Type) == 'Folder':
            async for item in self.walk(str(df)):
                yield item
        else:
            yield df