Skip to main content

Interactive Console (REPL)

Framework M provides a powerful interactive console for data exploration, debugging, and rapid prototyping. It is built on top of IPython and automatically handles dependency injection and application hydration.

note

The enhanced interactive console and the m cockpit object are features provided by the framework-m-studio package. If only the core framework is installed, you will have access to a basic Python shell instead.

Starting the Console

Use the m console command. To automatically initialize the dependency injection (DI) container and discover all DocTypes and services, use the --with-container flag.

uv run m console --with-container

The m Object (Developer Cockpit)

When starting the console with the --with-container flag, a global m object is injected into your namespace. This object provides ergonomic shortcuts to commonly used framework services, avoiding the boilerplate of manual DI resolution.

1. Database Access (m.session)

Get a managed SQLAlchemy async session context manager.

async with m.session as session:
# The 'session' object is a standard SQLAlchemy AsyncSession
pass

2. Repository Access (m.repo())

Get a repository for any DocType by name or class.

from my_app.doctypes import User

# Resolve by DocType class
urepo = m.repo(User)

# Resolve by name (string)
urepo = m.repo("User")

async with m.session as s:
response = await urepo.list_entities(s)
# response.items contains the list of entities
print(response.items)

3. Background Jobs (m.jobs)

Access the global JobRegistry to inspect or trigger jobs.

# List all discovered jobs
print(m.jobs.list_jobs())

4. Configuration (m.config)

Access the active RootConfig and application settings.

# Access a config value
print(m.config.get("database_url"))

5. Metadata (m.metadata)

Access the active SQLAlchemy MetaData object containing all discovered tables.

# List all tables in the metadata
print(m.metadata.tables.keys())

Tips & Tricks

Top-level Await

The console is built on IPython, which supports top-level await. You don't need to wrap your async calls in a function or use asyncio.run().

# This works directly in the console
async with m.session as s:
users = await m.repo("User").list_entities(s)

Paginated Results

Most repository methods (like list_entities) return a PaginatedResponse. Always access the results via the .items attribute:

response = await urepo.list_entities(s)
for item in response.items:
print(item.name)

info

The m object is only available when using the --with-container flag. Without it, you are in a "naked" Python shell with no framework hydration.