Skip to main content

Interactive Shell (Tinker)

Fastman's tinker command provides an interactive Python shell with your application context pre-loaded. Inspired by Laravel's Tinker, it's perfect for quick debugging, data exploration, and testing.

Basic Usageโ€‹

fastman tinker

This starts an interactive Python shell with:

  • Database session (db)
  • Application settings (settings)
  • SQLAlchemy Base model
  • All your models auto-imported

Featuresโ€‹

Pre-loaded Database Sessionโ€‹

>>> from app.features.user.models import User
>>> users = db.query(User).all()
>>> len(users)
42

IPython Supportโ€‹

If IPython is installed, tinker uses it automatically for:

  • Syntax highlighting
  • Tab completion
  • Better tracebacks
  • Magic commands (%history, %timeit, etc.)
pip install ipython
fastman tinker

Tinker Tricksโ€‹

1. Quick Data Inspectionโ€‹

# Count records
>>> db.query(User).count()
150

# Get first/last
>>> db.query(User).first()
<User id=1 email='admin@example.com'>

>>> db.query(User).order_by(User.id.desc()).first()
<User id=150 email='latest@example.com'>

# Filter with conditions
>>> db.query(User).filter(User.is_active == True).count()
142

2. Create Test Data Quicklyโ€‹

>>> from app.features.user.models import User
>>> user = User(email="test@example.com", name="Test User")
>>> db.add(user)
>>> db.commit()
>>> user.id
151

3. Update Recordsโ€‹

>>> user = db.query(User).filter(User.email == "test@example.com").first()
>>> user.name = "Updated Name"
>>> db.commit()

4. Delete Recordsโ€‹

>>> user = db.query(User).filter(User.id == 151).first()
>>> db.delete(user)
>>> db.commit()

5. Raw SQL Queriesโ€‹

>>> from sqlalchemy import text
>>> result = db.execute(text("SELECT COUNT(*) FROM users"))
>>> result.scalar()
150

6. Explore Relationshipsโ€‹

>>> user = db.query(User).first()
>>> user.posts # Lazy load related posts
[<Post id=1>, <Post id=2>, <Post id=3>]

>>> user.orders[-1].total # Latest order total
Decimal('99.99')

7. Test Servicesโ€‹

>>> from app.features.user.service import UserService
>>> service = UserService(db)
>>> service.get_active_users()
[<User id=1>, <User id=2>, ...]

8. Inspect Model Schemaโ€‹

>>> User.__table__.columns.keys()
['id', 'email', 'name', 'password', 'is_active', 'created_at']

>>> for col in User.__table__.columns:
... print(f"{col.name}: {col.type}")
id: INTEGER
email: VARCHAR(255)
name: VARCHAR(100)
...

9. Check Environmentโ€‹

>>> settings.DATABASE_URL
'postgresql://localhost/myapp'

>>> settings.DEBUG
True

>>> settings.SECRET_KEY[:10]
'abc123...'

10. Bulk Operationsโ€‹

# Bulk insert
>>> users = [User(email=f"user{i}@test.com") for i in range(100)]
>>> db.add_all(users)
>>> db.commit()

# Bulk update
>>> db.query(User).filter(User.is_active == False).update({"is_active": True})
>>> db.commit()

# Bulk delete
>>> db.query(User).filter(User.email.like("%@test.com")).delete()
>>> db.commit()

IPython Magic Commandsโ€‹

When using IPython, these magic commands are helpful:

CommandDescription
%historyShow command history
%timeitTime execution of a statement
%whoList all variables
%whosDetailed variable list
%resetClear all variables
%pastePaste from clipboard
%editOpen editor for multi-line code

Example: Timing Queriesโ€‹

>>> %timeit db.query(User).filter(User.is_active == True).all()
2.34 ms ยฑ 123 ยตs per loop

Tipsโ€‹

Use Rollback for Safety

When experimenting with data changes, wrap operations in a transaction you can rollback:

>>> user.name = "Oops"
>>> db.rollback() # Undo changes
Exit Cleanly

Always use exit() or Ctrl+D to exit tinker, which properly closes the database connection.

Production Caution

Be careful running tinker in production! Any database changes are permanent. Consider using a read-only database connection for production debugging.