Skip to content

pygx.io

Pluggable IO with unified interfaces.

io

Pluggable IO with unified interfaces.

pygx.io defines abstract FileSystem and File interfaces, plus a Sequence abstraction for append-only line-by-line streams. Implementations include:

  • An in-memory backend (MemoryFile, MemoryFileSystem, MemorySequence) useful for tests and ephemeral fixtures.
  • A fsspec bridge (FsspecFile, FsspecFileSystem) that delegates to any filesystem registered with fsspec (local, GCS, S3, etc.).
  • A line-based sequence type (LineSequence, LineSequenceIO) used by JSONL serialization in pg.open_jsonl.

External code can register additional FileSystem implementations and have the rest of PyGX (save/load/open_jsonl) pick them up transparently.

File

Interface for a file.

read abstractmethod

read(size: int | None = None) -> str | bytes

Reads the content of the file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def read(self, size: int | None = None) -> str | bytes:
    """Reads the content of the file."""

readline abstractmethod

readline() -> str | bytes

Reads the next line.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def readline(self) -> str | bytes:
    """Reads the next line."""

write abstractmethod

write(content: str | bytes) -> None

Writes the content of the file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def write(self, content: str | bytes) -> None:
    """Writes the content of the file."""

seek abstractmethod

seek(offset: int, whence: Literal[0, 1, 2] = 0) -> int

Changes the current position of the file.

Parameters:

Name Type Description Default
offset int

Offset from the position to a reference point.

required
whence Literal[0, 1, 2]

The reference point, with 0 meaning the beginning of the file, 1 meaning the current position, or 2 meaning the end of the file.

0

Returns:

Type Description
int

The position from the beginning of the file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def seek(self, offset: int, whence: Literal[0, 1, 2] = 0) -> int:
    """Changes the current position of the file.

    Args:
      offset: Offset from the position to a reference point.
      whence: The reference point, with 0 meaning the beginning of the file,
        1 meaning the current position, or 2 meaning the end of the file.

    Returns:
      The position from the beginning of the file.
    """

tell abstractmethod

tell() -> int

Returns the current position of the file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def tell(self) -> int:
    """Returns the current position of the file."""

flush abstractmethod

flush() -> None

Flushes the written content to the storage.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def flush(self) -> None:
    """Flushes the written content to the storage."""

close abstractmethod

close() -> None

Closes the file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def close(self) -> None:
    """Closes the file."""

FileSystem

Interface for a file system.

open abstractmethod

open(path: str | PathLike[str], mode: str = 'r', **kwargs) -> File

Opens a file with a path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def open(
    self, path: str | os.PathLike[str], mode: str = 'r', **kwargs
) -> File:
    """Opens a file with a path."""

chmod abstractmethod

chmod(path: str | PathLike[str], mode: int) -> None

Changes the permission of a file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def chmod(self, path: str | os.PathLike[str], mode: int) -> None:
    """Changes the permission of a file."""

exists abstractmethod

exists(path: str | PathLike[str]) -> bool

Returns True if a path exists.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def exists(self, path: str | os.PathLike[str]) -> bool:
    """Returns True if a path exists."""

glob abstractmethod

glob(pattern: str | PathLike[str]) -> list[str]

Lists all files or sub-directories.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def glob(self, pattern: str | os.PathLike[str]) -> list[str]:
    """Lists all files or sub-directories."""

listdir abstractmethod

listdir(path: str | PathLike[str]) -> list[str]

Lists all files or sub-directories.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def listdir(self, path: str | os.PathLike[str]) -> list[str]:
    """Lists all files or sub-directories."""

isdir abstractmethod

isdir(path: str | PathLike[str]) -> bool

Returns True if a path is a directory.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def isdir(self, path: str | os.PathLike[str]) -> bool:
    """Returns True if a path is a directory."""

getctime abstractmethod

getctime(path: str | PathLike[str]) -> float

Returns the creation time of a file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def getctime(self, path: str | os.PathLike[str]) -> float:
    """Returns the creation time of a file."""

getmtime abstractmethod

getmtime(path: str | PathLike[str]) -> float

Returns the last modification time of a file.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def getmtime(self, path: str | os.PathLike[str]) -> float:
    """Returns the last modification time of a file."""

mkdir abstractmethod

mkdir(path: str | PathLike[str], mode: int = 511) -> None

Makes a directory based on a path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def mkdir(self, path: str | os.PathLike[str], mode: int = 0o777) -> None:
    """Makes a directory based on a path."""

mkdirs abstractmethod

mkdirs(
    path: str | PathLike[str], mode: int = 511, exist_ok: bool = True
) -> None

Makes a directory chain based on a path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def mkdirs(
    self,
    path: str | os.PathLike[str],
    mode: int = 0o777,
    exist_ok: bool = True,
) -> None:
    """Makes a directory chain based on a path."""

rm abstractmethod

rm(path: str | PathLike[str]) -> None

Removes a file based on a path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def rm(self, path: str | os.PathLike[str]) -> None:
    """Removes a file based on a path."""

rename abstractmethod

rename(oldpath: str | PathLike[str], newpath: str | PathLike[str]) -> None

Renames a file based on a path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def rename(
    self,
    oldpath: str | os.PathLike[str],
    newpath: str | os.PathLike[str],
) -> None:
    """Renames a file based on a path."""

rmdir abstractmethod

rmdir(path: str | PathLike[str]) -> None

Removes a directory based on a path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def rmdir(self, path: str | os.PathLike[str]) -> None:
    """Removes a directory based on a path."""

rmdirs abstractmethod

rmdirs(path: str | PathLike[str]) -> None

Removes a directory chain based on a path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def rmdirs(self, path: str | os.PathLike[str]) -> None:
    """Removes a directory chain based on a path."""

copy abstractmethod

copy(oldpath: str | PathLike[str], newpath: str | PathLike[str]) -> None

Copies a file to a new path.

Source code in pygx/io/_file_system.py
@abc.abstractmethod
def copy(
    self,
    oldpath: str | os.PathLike[str],
    newpath: str | os.PathLike[str],
) -> None:
    """Copies a file to a new path."""

StdFile

StdFile(file_object, path: str | PathLike[str])

Bases: File

The standard file.

Source code in pygx/io/_file_system.py
def __init__(self, file_object, path: str | os.PathLike[str]) -> None:
    super().__init__()
    self._file_object = file_object
    self._path = path

StdFileSystem

Bases: FileSystem

The standard file system.

MemoryFile

MemoryFile(buffer: IOBase)

Bases: File

Memory file.

Source code in pygx/io/_file_system.py
def __init__(self, buffer: io.IOBase):
    super().__init__()
    self._buffer = buffer
    self._pos = 0
    now = datetime.datetime.now().timestamp()
    self.ctime = now
    self.mtime = now

MemoryFileSystem

MemoryFileSystem(prefix: str = '/mem/')

Bases: FileSystem

The in-memory file system.

Source code in pygx/io/_file_system.py
def __init__(self, prefix: str = '/mem/'):
    super().__init__()
    self._root = {}
    self._prefix = prefix

getctime

getctime(path: str | PathLike[str]) -> float

Returns the creation time of a file.

Source code in pygx/io/_file_system.py
def getctime(self, path: str | os.PathLike[str]) -> float:
    """Returns the creation time of a file."""
    f = self._locate(path)
    if isinstance(f, dict):
        raise IsADirectoryError(path)
    if f is None:
        raise FileNotFoundError(path)
    return f.ctime

getmtime

getmtime(path: str | PathLike[str]) -> float

Returns the last modification time of a file.

Source code in pygx/io/_file_system.py
def getmtime(self, path: str | os.PathLike[str]) -> float:
    """Returns the last modification time of a file."""
    f = self._locate(path)
    if isinstance(f, dict):
        raise IsADirectoryError(path)
    if f is None:
        raise FileNotFoundError(path)
    return f.mtime

FsspecFile

FsspecFile(f)

Bases: File

File object based on fsspec.

Source code in pygx/io/_file_system.py
def __init__(self, f):
    self._f = f

FsspecFileSystem

Bases: FileSystem

File system based on fsspec.

Sequence

Sequence(
    perms: int | None = None,
    serializer: Callable[[Any], bytes | str] | None = None,
    deserializer: Callable[[bytes | str], Any] | None = None,
)

Interface for a sequence of records.

Source code in pygx/io/_sequence.py
def __init__(
    self,
    perms: int | None = None,
    serializer: Callable[[Any], bytes | str] | None = None,
    deserializer: Callable[[bytes | str], Any] | None = None,
):
    self._perms = perms
    self._serializer = serializer
    self._deserializer = deserializer

add

add(record: Any) -> None

Adds a record to the reader.

Source code in pygx/io/_sequence.py
def add(self, record: Any) -> None:
    """Adds a record to the reader."""
    if self._serializer:
        record = self._serializer(record)
    if not isinstance(record, (str, bytes)):
        raise ValueError(
            f'Cannot write record with type {type(record)}. '
            'Did you forget to pass a serializer?'
        )
    self._add(record)

close abstractmethod

close() -> None

Closes the reader.

Source code in pygx/io/_sequence.py
@abc.abstractmethod
def close(self) -> None:
    """Closes the reader."""

flush abstractmethod

flush() -> None

Flushes the read records to the storage.

Source code in pygx/io/_sequence.py
@abc.abstractmethod
def flush(self) -> None:
    """Flushes the read records to the storage."""

SequenceIO

Interface for a record IO system.

open abstractmethod

open(
    path: str | PathLike[str],
    mode: str,
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
    **kwargs
) -> Sequence

Opens a sequence for reading or writing.

Source code in pygx/io/_sequence.py
@abc.abstractmethod
def open(
    self,
    path: str | os.PathLike[str],
    mode: str,
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
    **kwargs,
) -> Sequence:
    """Opens a sequence for reading or writing."""

MemorySequence

MemorySequence(
    path: str | PathLike[str],
    mode: str,
    records: list[str | bytes],
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None
)

Bases: Sequence

An in-memory sequence.

Source code in pygx/io/_sequence.py
def __init__(
    self,
    path: str | os.PathLike[str],
    mode: str,
    records: list[str | bytes],
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
):
    super().__init__(perms, serializer, deserializer)
    self._path = path
    self._mode = mode
    self._records = records
    self._closed = False

MemorySequenceIO

MemorySequenceIO()

Bases: SequenceIO

Memory-based record IO.

Source code in pygx/io/_sequence.py
def __init__(self):
    super().__init__()
    self._root = collections.defaultdict(list)

open

open(
    path: str | PathLike[str],
    mode: str,
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
    **kwargs
) -> Sequence

Opens a reader for a sequence.

Source code in pygx/io/_sequence.py
def open(
    self,
    path: str | os.PathLike[str],
    mode: str,
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
    **kwargs,
) -> Sequence:
    """Opens a reader for a sequence."""
    del kwargs
    if 'w' in mode:
        self._root[path] = []
    return MemorySequence(
        path,
        mode,
        self._root[path],
        perms=perms,
        serializer=serializer,
        deserializer=deserializer,
    )

LineSequence

LineSequence(
    path: str | PathLike[str],
    mode: str,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
)

Bases: Sequence

A new-line broken sequence.

Source code in pygx/io/_sequence.py
def __init__(
    self,
    path: str | os.PathLike[str],
    mode: str,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
) -> None:
    super().__init__(perms, serializer, deserializer)
    self._path = path
    self._mode = mode
    self._file = file_system.open(path, mode)

LineSequenceIO

Bases: SequenceIO

Line-based record IO.

open

open(
    path: str | PathLike[str],
    mode: str,
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
    **kwargs
) -> Sequence

Opens a reader for a sequence.

Source code in pygx/io/_sequence.py
def open(
    self,
    path: str | os.PathLike[str],
    mode: str,
    *,
    perms: int | None,
    serializer: Callable[[Any], bytes | str] | None,
    deserializer: Callable[[bytes | str], Any] | None,
    **kwargs,
) -> Sequence:
    """Opens a reader for a sequence."""
    del kwargs
    return LineSequence(path, mode, perms, serializer, deserializer)

add_file_system

add_file_system(prefix: str, fs: FileSystem) -> None

Adds a file system with a prefix.

Source code in pygx/io/_file_system.py
def add_file_system(prefix: str, fs: FileSystem) -> None:
    """Adds a file system with a prefix."""
    _fs.add(prefix, fs)

open

open(path: str | PathLike[str], mode: str = 'r', **kwargs) -> File

Opens a file with a path.

Source code in pygx/io/_file_system.py
def open(path: str | os.PathLike[str], mode: str = 'r', **kwargs) -> File:  # pylint:disable=redefined-builtin
    """Opens a file with a path."""
    return _fs.get(path).open(path, mode, **kwargs)

chmod

chmod(path: str | PathLike[str], mode: int) -> None

Changes the permission of a file.

Source code in pygx/io/_file_system.py
def chmod(path: str | os.PathLike[str], mode: int) -> None:
    """Changes the permission of a file."""
    _fs.get(path).chmod(path, mode)

readfile

readfile(
    path: str | PathLike[str],
    mode: str = "r",
    nonexist_ok: bool = False,
    **kwargs
) -> bytes | str | None

Reads content from a file.

Source code in pygx/io/_file_system.py
def readfile(
    path: str | os.PathLike[str],
    mode: str = 'r',
    nonexist_ok: bool = False,
    **kwargs,
) -> bytes | str | None:
    """Reads content from a file."""
    try:
        with _fs.get(path).open(path, mode=mode, **kwargs) as f:
            return f.read()
    except FileNotFoundError as e:
        if nonexist_ok:
            return None
        raise e

writefile

writefile(
    path: str | PathLike[str],
    content: str | bytes,
    *,
    mode: str = "w",
    perms: int | None = 436,
    **kwargs
) -> None

Writes content to a file.

Source code in pygx/io/_file_system.py
def writefile(
    path: str | os.PathLike[str],
    content: str | bytes,
    *,
    mode: str = 'w',
    perms: int | None = 0o664,  # Default to world-readable.
    **kwargs,
) -> None:
    """Writes content to a file."""
    with _fs.get(path).open(path, mode=mode, **kwargs) as f:
        f.write(content)
    if perms is not None:
        chmod(path, perms)

rename

rename(oldpath: str | PathLike[str], newpath: str | PathLike[str]) -> None

Renames a file.

Source code in pygx/io/_file_system.py
def rename(
    oldpath: str | os.PathLike[str],
    newpath: str | os.PathLike[str],
) -> None:
    """Renames a file."""
    _fs.get(oldpath).rename(oldpath, newpath)

rm

rm(path: str | PathLike[str]) -> None

Removes a file.

Source code in pygx/io/_file_system.py
def rm(path: str | os.PathLike[str]) -> None:
    """Removes a file."""
    _fs.get(path).rm(path)

copy

copy(oldpath: str | PathLike[str], newpath: str | PathLike[str]) -> None

Copies a file.

Source code in pygx/io/_file_system.py
def copy(
    oldpath: str | os.PathLike[str],
    newpath: str | os.PathLike[str],
) -> None:
    """Copies a file."""
    _fs.get(oldpath).copy(oldpath, newpath)

path_exists

path_exists(path: str | PathLike[str]) -> bool

Returns True if path exists.

Source code in pygx/io/_file_system.py
def path_exists(path: str | os.PathLike[str]) -> bool:
    """Returns True if path exists."""
    return _fs.get(path).exists(path)

glob

glob(pattern: str | PathLike[str]) -> list[str]

Lists all files or sub-directories.

Source code in pygx/io/_file_system.py
def glob(pattern: str | os.PathLike[str]) -> list[str]:
    """Lists all files or sub-directories."""
    return _fs.get(pattern).glob(pattern)

listdir

listdir(path: str | PathLike[str], fullpath: bool = False) -> list[str]

Lists all files or sub-directories under a dir.

Source code in pygx/io/_file_system.py
def listdir(path: str | os.PathLike[str], fullpath: bool = False) -> list[str]:  # pylint: disable=redefined-builtin
    """Lists all files or sub-directories under a dir."""
    entries = _fs.get(path).listdir(path)
    if fullpath:
        return [os.path.join(path, entry) for entry in entries]
    return entries

isdir

isdir(path: str | PathLike[str]) -> bool

Returns True if path is a directory.

Source code in pygx/io/_file_system.py
def isdir(path: str | os.PathLike[str]) -> bool:
    """Returns True if path is a directory."""
    return _fs.get(path).isdir(path)

getctime

getctime(path: str | PathLike[str]) -> float

Returns the creation time of a file.

Source code in pygx/io/_file_system.py
def getctime(path: str | os.PathLike[str]) -> float:
    """Returns the creation time of a file."""
    return _fs.get(path).getctime(path)

getmtime

getmtime(path: str | PathLike[str]) -> float

Returns the last modification time of a file.

Source code in pygx/io/_file_system.py
def getmtime(path: str | os.PathLike[str]) -> float:
    """Returns the last modification time of a file."""
    return _fs.get(path).getmtime(path)

mkdir

mkdir(path: str | PathLike[str], mode: int = 511) -> None

Makes a directory.

Source code in pygx/io/_file_system.py
def mkdir(path: str | os.PathLike[str], mode: int = 0o777) -> None:
    """Makes a directory."""
    _fs.get(path).mkdir(path, mode=mode)

mkdirs

mkdirs(
    path: str | PathLike[str], mode: int = 511, exist_ok: bool = True
) -> None

Makes a directory chain.

Source code in pygx/io/_file_system.py
def mkdirs(
    path: str | os.PathLike[str],
    mode: int = 0o777,
    exist_ok: bool = True,
) -> None:
    """Makes a directory chain."""
    _fs.get(path).mkdirs(path, mode=mode, exist_ok=exist_ok)

rmdir

rmdir(path: str | PathLike[str]) -> None

Removes a directory.

Source code in pygx/io/_file_system.py
def rmdir(path: str | os.PathLike[str]) -> None:
    """Removes a directory."""
    _fs.get(path).rmdir(path)

rmdirs

rmdirs(path: str | PathLike[str]) -> None

Removes a directory chain until a parent directory is not empty.

Source code in pygx/io/_file_system.py
def rmdirs(path: str | os.PathLike[str]) -> None:
    """Removes a directory chain until a parent directory is not empty."""
    _fs.get(path).rmdirs(path)

add_sequence_io

add_sequence_io(extension: str, sequence_io: SequenceIO) -> None

Adds a record IO system with a prefix.

Source code in pygx/io/_sequence.py
def add_sequence_io(extension: str, sequence_io: SequenceIO) -> None:
    """Adds a record IO system with a prefix."""
    _registry.add(extension, sequence_io)

open_sequence

open_sequence(
    path: str | PathLike[str],
    mode: str = "r",
    *,
    perms: int | None = 436,
    serializer: Callable[[Any], bytes | str] | None = None,
    deserializer: Callable[[bytes | str], Any] | None = None,
    make_dirs_if_not_exist: bool = True
) -> Sequence

Open sequence for reading or writing.

Parameters:

Name Type Description Default
path str | PathLike[str]

The path to the sequence.

required
mode str

The mode of the sequence.

'r'
perms int | None

(Optional) The permissions of the sequence.

436
serializer Callable[[Any], bytes | str] | None

(Optional) A serializer function for converting a structured object to a string or bytes.

None
deserializer Callable[[bytes | str], Any] | None

(Optional) A deserializer function for converting a string or bytes to a structured object.

None
make_dirs_if_not_exist bool

(Optional) Whether to create the directories if they do not exist. Applicable when opening in write or append mode.

True

Returns:

Type Description
Sequence

A sequence for reading or writing.

Source code in pygx/io/_sequence.py
def open_sequence(
    path: str | os.PathLike[str],
    mode: str = 'r',
    *,
    perms: int | None = 0o664,  # Default to world-readable.
    serializer: Callable[[Any], bytes | str] | None = None,
    deserializer: Callable[[bytes | str], Any] | None = None,
    make_dirs_if_not_exist: bool = True,
) -> Sequence:
    """Open sequence for reading or writing.

    Args:
      path: The path to the sequence.
      mode: The mode of the sequence.
      perms: (Optional) The permissions of the sequence.
      serializer: (Optional) A serializer function for converting a structured
        object to a string or bytes.
      deserializer: (Optional) A deserializer function for converting a string or
        bytes to a structured object.
      make_dirs_if_not_exist: (Optional) Whether to create the directories
        if they do not exist. Applicable when opening in write or append mode.

    Returns:
      A sequence for reading or writing.
    """
    if 'w' in mode or 'a' in mode:
        parent_dir = os.path.dirname(path)
        if make_dirs_if_not_exist:
            file_system.mkdirs(parent_dir, exist_ok=True)
    return _registry.get(path).open(
        path,
        mode,
        perms=perms,
        serializer=serializer,
        deserializer=deserializer,
    )

options: show_root_heading: false show_root_toc_entry: false members_order: source heading_level: 2