packages

File System

Object-style File and Directory classes, the same shape as the new expo-file-system API. Reads and writes are plain Python file I/O, so they are fast and work the same everywhere. Downloads use URLSession on iOS and HttpURLConnection on Android. Every method also has its Expo camelCase name.

  • pyxpo-file-system
  • v0.1.0a1
  • Native: Swift + Kotlin
  • Like expo-file-system

Install

Install the package into the same environment as pyxpo.

$pip install pyxpo-file-system

Add file-system to modules in your app config, then import it in your code.

pyproject.toml
[tool.pyxpo]
modules = ["file-system"]
python
from pyxpo_file_system import File, Directory, Paths

This module has native code. After you add it, run pyxpo run or pyxpo build again so it is compiled into the app. Hot reload alone is not enough.

Platforms

iOSDocuments and Caches folders
Androidfiles and cache folders
Desktop previewWorks. Downloads use urllib

Quick start

app/index.py
from pyxpo_file_system import File, Paths

note = File(Paths.document, "note.txt")
note.write("Hello from Python")

print(note.text_sync())   # Hello from Python
print(note.size)          # 17

Permissions

pyxpo adds these to Info.plist and AndroidManifest.xml for you when the module is listed.

iOSNone.
AndroidINTERNET, for downloads.

API reference

Paths

Paths.document→ Directory

Kept until the app is deleted. Backed up on iOS.

Paths.cache→ Directory

The system may clear it when space runs low.

Paths.available_disk_space / Paths.total_disk_space→ int

Bytes.

Paths.join(*parts) / dirname / basename(path, ext=None) / extname→ str

Path string helpers.

File

File(Paths.document, "a", "b.txt"), a file:// URI or an absolute path. Creating the object does not touch the disk.

uri / name / path / extension / parent_directory

Where the file is.

exists / size / md5 / modification_time / creation_time / type

Live values read from the disk.

text_sync() / bytes_sync() / base64_sync()→ str | bytes

Reads the whole file.

await text() / await bytes() / await base64()→ str | bytes

Async versions.

write(content, options=None, *, encoding="utf8", append=None)

Writes str or bytes. encoding="base64" decodes a base64 string first. The folder must exist.

create(options=None, *, intermediates=None, overwrite=None)

Creates an empty file. intermediates=True creates missing folders.

copy(dest) / move(dest) / rename(new_name) / delete()

dest is a File or a Directory.

info(options=None, *, md5=None)→ dict

{exists, uri, size, modificationTime, creationTime, md5?}. Times are in milliseconds.

open()→ FileHandle

Random access: offset, size, read_bytes(n), write_bytes(data), close().

Downloads

await File.download_file_async(url, destination, options=None)→ File

Downloads to a File or a Directory. A Directory keeps the server's file name. Raises on a non-2xx status. Options: {"headers": {...}, "idempotent": True} where idempotent replaces an existing file.

Directory

uri / exists / size

size is the total of all files inside.

create(options=None, *, intermediates=None, overwrite=None, idempotent=None)

idempotent=True does nothing when the folder exists.

list()→ list[File | Directory]

Direct children.

list_as_records()→ list[dict]

Children as plain records.

create_file(name, mime_type=None) / create_directory(name)

Creates a child.

copy / move / rename / delete / info()

Same as File.

Legacy API

The classic expo-file-system functions, for code ported from Expo SDK 53 and older.

from pyxpo_file_system import legacy as FileSystem

documentDirectory, get_info_async, read_as_string_async, write_as_string_async, delete_async, move_async, copy_async, make_directory_async, read_directory_async, download_async, get_free_disk_storage_async. camelCase aliases also work.

Examples

Save and load JSON

Keep app data in a folder inside Paths.document.

python
import json
from pyxpo_file_system import Directory, File, Paths

folder = Directory(Paths.document, "notes")
folder.create(idempotent=True)

f = File(folder, "today.json")
f.write(json.dumps({"title": "Groceries", "done": False}))

data = json.loads(f.text_sync())
names = [item.name for item in folder.list()]

Download a file

Download into the cache folder and keep the server's file name.

python
from pyxpo_file_system import Directory, File, Paths

async def fetch_report():
    dest = Directory(Paths.cache, "downloads")
    dest.create(intermediates=True, idempotent=True)
    out = await File.download_file_async(
        "https://example.com/report.pdf", dest,
        {"idempotent": True, "headers": {"Accept": "application/pdf"}},
    )
    return out.uri

Read part of a large file

Use a FileHandle to read bytes from any position without loading the whole file.

python
from pyxpo_file_system import File, Paths

h = File(Paths.document, "video.mp4").open()
h.offset = 1024
header = h.read_bytes(64)
h.close()

Good to know

  • File and Directory objects are cheap. They only point at a path until you call a method.
  • Writing into a folder that does not exist raises an error. Create it first, or use create(intermediates=True).
  • Files from the image picker are in the cache folder. Copy them to Paths.document to keep them.