SessionContext Frozen Dataclass
π Overview
SessionContext is an immutable dataclass designed to hold the execution context for a shell or REPL environment across multiple command invocations. It preserves the current working directory, a dictionary of environment variables, and the active character encoding. Because the class is frozen (frozen=True), instances are hashable and threadβsafe, encouraging explicit state transitions via replacement or factory methods.
π¦ Class Definition
@dataclass(frozen=True)
class SessionContext:
"""Maintains persistent state across Shell executions."""
cwd: Path = field(default_factory=Path.cwd)
env: Dict[str, str] = field(default_factory=dict)
encoding: str = "utf-8"
The frozen decorator guarantees immutability after construction. All fields are readβonly, making SessionContext ideal for functional updates or storing in caches.
| Parameter | Type | Description |
|---|---|---|
cwd | Path | Current working directory for shell commands. Defaults to the system's current working directory via Path.cwd(). |
env | Dict[str, str] | Environment variables as key-value pairs. Initially an empty dictionary. |
encoding | str | Character encoding used for I/O operations (e.g., subprocess or file handling). Defaults to "utf-8". |
β¨ Immutability & Default Factories
field(default_factory=Path.cwd) ensures that each new instance computes a fresh cwd value at runtime, rather than sharing a single path reference. Similarly, env uses default_factory=dict to create independent environment dictionaries. Because the dataclass is frozen, you cannot mutate cwd or env after creation β any change produces a new instance.
π Attributes & Field Behavior
The three primary attributes define the persistent session contract. Below you'll find deeper insight into each field:
cwd : Path
Current Working Directory β any relative paths executed in the shell will resolve relative to this directory. The default value is obtained via Path.cwd() at instantiation time, meaning each SessionContext captures the actual process working directory on creation. Frozen state guarantees that the working directory cannot be changed without creating a new context.
env : Dict[str, str]
Environment Variables Dictionary β stores key-value string pairs that represent shell environment variables. This dictionary is independent per instance (default factory ensures unique dict). For typical shell usage, this may include PATH, HOME, or custom variables. Because the context is frozen, the dictionary is also readβonly; to update environment variables you must create a new context (e.g., using replace or by constructing a fresh instance).
encoding : str
Character Encoding β defines the text encoding for standard streams, file I/O, and subprocess communication. The default is "utf-8", the modern standard. Changing the encoding allows compatibility with legacy systems or different locales.
π Field Summary
| Field | Type | Default | Immutability |
|---|---|---|---|
cwd | Path | Path.cwd() (dynamic) | Frozen β read-only |
env | Dict[str, str] | {} (new dict per instance) | Frozen β read-only |
encoding | str | "utf-8" | Frozen β read-only |
βοΈ Usage Examples
Typical patterns for constructing and βupdatingβ a SessionContext in a persistent shell environment. Since the class is frozen, modifications produce new instances β this aligns with functional state management.
π Basic instantiation
from pathlib import Path
from dataclasses import dataclass, field
from typing import Dict
# Assuming SessionContext definition from above
initial_context = SessionContext()
print(initial_context.cwd) # /current/working/directory
print(initial_context.env) # {}
print(initial_context.encoding) # utf-8
π Custom session with specific working directory & env
custom_env = {"EDITOR": "vim", "LANG": "en_US.UTF-8"}
project_context = SessionContext(
cwd=Path("/home/user/projects/myapp"),
env=custom_env,
encoding="utf-8"
)
# Access fields
print(project_context.env["EDITOR"]) # vim
π Updating context (immutable approach)
Because frozen=True disables direct assignment, use dataclasses.replace or construct new contexts:
from dataclasses import replace
# create new context with changed cwd
old_ctx = SessionContext(cwd=Path("/initial/path"))
new_ctx = replace(old_ctx, cwd=Path("/new/workspace"))
print(old_ctx.cwd) # /initial/path
print(new_ctx.cwd) # /new/workspace
# To update environment variables, merge and create a fresh instance
updated_env = {**old_ctx.env, "NEW_VAR": "value"}
refreshed_ctx = replace(old_ctx, env=updated_env)
π Shell REPL state machine pattern
class ShellExecutor:
def __init__(self, context: SessionContext):
self._context = context
def run_command(self, cmd: str) -> str:
# use self._context.cwd, self._context.env, self._context.encoding
# simulate execution ...
return f"Executed '{cmd}' in {self._context.cwd}"
def change_directory(self, new_path: Path) -> 'ShellExecutor':
new_ctx = replace(self._context, cwd=new_path)
return ShellExecutor(new_ctx)
# usage:
shell = ShellExecutor(SessionContext())
shell = shell.change_directory(Path("/var/log"))
π§ Behavior & Design Notes
@dataclass(frozen=True) decorator makes the class hashable and prevents accidental mutation. However, note that the env dictionary itself is a mutable container; the frozen dataclass only prevents reassigning env attribute. To preserve deep immutability, avoid mutating the dictionary after creation β instead always replace the entire env via a new instance.
- β Thread safety: Immutable contexts can be safely shared across threads without locking.
- β Default factory semantics:
Path.cwd()is evaluated at construction, not at class definition. So each instance gets the current directory of the Python process at that moment. - β Serialization: Because it's a dataclass, you can easily serialize to JSON or dict:
asdict(context). - β Equality & Hashing: Two contexts with identical
cwd,env, andencodingare considered equal and produce the same hash β useful for caching.
π Advanced considerations
Environment variable fallback: While the env dictionary is empty by default, in a real shell you may want to preβpopulate it with os.environ.copy(). The design intentionally leaves this decision to the caller, making the context lightweight.
Encoding validation: The encoding attribute is a simple string; consumers should validate against Python's codecs.lookup() if needed. The class does not perform runtime checks to keep overhead minimal.
π Relationship with Shell Executor
SessionContext is meant to be used as an immutable state carrier for a shell loop or command processor. Instead of mutating global state, each command can receive the current context and optionally return a new context for the next iteration. This reduces bugs and makes history/replay possible.
π API Reference Summary
Class: SessionContext (frozen dataclass)
Module: shell.context (assumed)
Since: core shell abstraction
@dataclass(frozen=True) ensures the shell session state is predictable. For any modifications, the consumer must produce a new instance β enabling clean rollback and snapshot capabilities.
See also: dataclasses.replace utility to create modified copies without boilerplate.