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
mcockpit object are features provided by theframework-m-studiopackage. 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)
[!IMPORTANT] The
mobject is only available when using the--with-containerflag. Without it, you are in a "naked" Python shell with no framework hydration.