ExMonty.PseudoFS (ExMonty v0.5.0)

Copy Markdown View Source

An in-memory virtual filesystem for sandboxed Python execution.

Python code running in monty can use pathlib.Path and os module functions, which yield :os_call progress events. PseudoFS provides a complete handler that responds to these calls using an in-memory filesystem, so Python code can read and write files without touching the real filesystem.

Usage

fs = ExMonty.PseudoFS.new()
  |> ExMonty.PseudoFS.put_file("/data/config.json", ~s({"key": "value"}))
  |> ExMonty.PseudoFS.put_file("/data/readme.txt", "Hello world")
  |> ExMonty.PseudoFS.mkdir("/data/output")
  |> ExMonty.PseudoFS.put_env("API_KEY", "sk-secret123")

{:ok, result, output} = ExMonty.Sandbox.run(code, os: fs)

With ExMonty.Sandbox

Pass the PseudoFS directly as the :os option — it implements the handler protocol expected by ExMonty.Sandbox:

{:ok, result, output} = ExMonty.Sandbox.run(
  "from pathlib import Path; Path('/data/config.json').read_text()",
  os: ExMonty.PseudoFS.new()
    |> ExMonty.PseudoFS.put_file("/data/config.json", "content")
)

Supported Operations

PythonOS FunctionNotes
Path.exists():existsChecks files and directories
Path.is_file():is_file
Path.is_dir():is_dir
Path.is_symlink():is_symlinkAlways False
Path.read_text():read_text
Path.read_bytes():read_bytes
Path.write_text(data):write_textCreates parent dirs
Path.write_bytes(data):write_bytesCreates parent dirs
Path.mkdir():mkdirSupports parents, exist_ok
Path.unlink():unlink
Path.rmdir():rmdirMust be empty
Path.iterdir():iterdirLists direct children
Path.stat():statReturns stat_result tuple
Path.rename(target):rename
Path.resolve():resolveReturns path as-is
Path.absolute():absoluteReturns path as-is
os.getenv(key):getenv
os.environ:get_environ

Summary

Functions

Handles an OS call against this pseudo filesystem.

Creates a directory.

Creates a new empty pseudo filesystem.

Adds a file with binary content.

Sets an environment variable.

Sets multiple environment variables from a map.

Adds a file with text content.

Types

t()

@type t() :: %ExMonty.PseudoFS{
  dirs: MapSet.t(),
  env: %{required(String.t()) => String.t()},
  files: %{required(String.t()) => {binary(), non_neg_integer()}},
  mtime: float()
}

Functions

handle_os(fs, function, args, kwargs \\ %{})

@spec handle_os(t(), atom(), list(), map()) ::
  {:ok, term()}
  | {:error, atom(), String.t()}
  | {t(), {:ok, term()}}
  | {t(), {:error, atom(), String.t()}}

Handles an OS call against this pseudo filesystem.

This is the dispatch function used by ExMonty.Sandbox. You can also call it directly when driving the interactive loop manually.

Returns {:ok, value} on success or {:error, exc_type, message} on failure.

mkdir(fs, path)

@spec mkdir(t(), String.t()) :: t()

Creates a directory.

Parent directories are created automatically.

new(opts \\ [])

@spec new(keyword()) :: t()

Creates a new empty pseudo filesystem.

Options

  • :mtime - default modification time as Unix timestamp (default: 1_700_000_000.0)

put_bytes(fs, path, content, opts \\ [])

@spec put_bytes(t(), String.t(), binary(), keyword()) :: t()

Adds a file with binary content.

Parent directories are created automatically.

put_env(fs, key, value)

@spec put_env(t(), String.t(), String.t()) :: t()

Sets an environment variable.

fs = PseudoFS.new() |> PseudoFS.put_env("API_KEY", "secret")

put_envs(fs, envs)

@spec put_envs(t(), %{required(String.t()) => String.t()}) :: t()

Sets multiple environment variables from a map.

put_file(fs, path, content, opts \\ [])

@spec put_file(t(), String.t(), binary(), keyword()) :: t()

Adds a file with text content.

Parent directories are created automatically.

fs = PseudoFS.new()
  |> PseudoFS.put_file("/etc/config.toml", "[settings]\nkey = \"value\"")

Options

  • :mode - file permission bits (default: 0o644)