# Scenario 09: Interactive Environments **Target Audience**: Data scientists, researchers, educators **Difficulty**: Beginner **Keywords**: jupyter, ipython, repl, notebooks, interactive, exploration --- ## 📋 The Problem Interactive environments (Jupyter, IPython, REPL) are designed for quick experimentation: **Traditional async in notebooks**: ```python # Verbose and annoying import asyncio async def fetch_data(url): # async code pass # Must use asyncio.run() or await (with special setup) data = asyncio.run(fetch_data(url)) # Every time! ``` **Problems**: - Breaks flow of exploration - Verbose for simple operations - Must remember asyncio.run() - Not beginner-friendly - Clutters notebook cells - Makes examples harder to follow **Especially painful for**: - Teaching async concepts - Data analysis with async APIs - Quick prototyping - Live demos - Tutorials and documentation --- ## 💡 Solution with SmartAsync **Natural, synchronous-looking code**: - Call async functions directly - No asyncio.run() needed - Clean notebook cells - Focus on logic, not machinery - Beginner-friendly **Pattern**: ```python # Notebook cell api = MyAsyncAPI() data = api.fetch(url) # Just works! df = pd.DataFrame(data) df.head() ``` Clean, readable, explorative. --- ## 🎯 When to Use **Ideal for**: - Jupyter notebooks - IPython REPL - Data exploration - Teaching/tutorials - API prototyping - Live coding demos - Documentation examples **Perfect when**: - Audience is not async experts - Focus is on data/logic, not infrastructure - Quick iteration needed - Teaching material - Client wants simple examples --- ## ⚠️ Considerations ### Notebook Best Practices **Cell organization**: - One logical operation per cell - Keep cells focused - Reusable functions - Clear progression **State management**: - Notebooks have mutable state - Restarting kernel helpful - Document cell order - Use "Run All" to verify **Performance**: - Each call spawns event loop - Fine for exploration - Not for production pipelines - Profile if performance critical ### Teaching Async **Progressive disclosure**: 1. Start with SmartAsync (simple) 2. Show it's async under the hood 3. Explain when/why await needed 4. Graduate to native async **Learning path**: - Beginners: Use without await - Intermediate: Understand mechanics - Advanced: Full async/await control ### Documentation Examples **Code examples**: - Show simplest form first - Mention async capability - Link to advanced usage - Keep examples runnable **Interactive docs**: - Binder links - Google Colab - Jupyter Book - nbviewer ### When NOT to Use **Avoid if**: - Teaching native async/await (use real async) - Production notebooks (consider proper async) - High-performance computing - Need explicit event loop control **Better alternatives**: - Native async with IPython's `await` support - Synchronous APIs (if available) - Batch processing scripts --- ## 🔗 Related Scenarios - **01: CLI Tools** - Similar simple interface pattern - **03: Testing** - Similar "call without await" pattern - **08: Web Scraping** - Prototyping scrapers in notebooks --- ## 📚 Interactive Tools **Jupyter ecosystem**: - **JupyterLab** - Modern notebook interface - **Jupyter Notebook** - Classic interface - **Google Colab** - Cloud notebooks - **Binder** - Shareable notebooks **REPL environments**: - **IPython** - Enhanced Python REPL - **ptpython** - Advanced REPL - **Python REPL** - Standard interpreter **Documentation tools**: - **Jupyter Book** - Executable books - **nbviewer** - Notebook viewer - **nbconvert** - Convert notebooks --- ## 🎯 Use Cases ### Data Science - Fetch data from async APIs - Parallel data loading - Live data exploration - API prototyping ### Education - Teaching async concepts - Interactive tutorials - Live coding sessions - Student exercises ### API Development - Testing API clients - Exploring responses - Quick iteration - Documentation examples ### Research - Data collection - API experimentation - Reproducible research - Sharing results --- ## 🔍 Notebook Patterns **Data fetching**: ```python # Cell 1: Setup from mylib import AsyncAPI api = AsyncAPI(token="...") # Cell 2: Fetch (simple!) data = api.get_dataset("users") # Cell 3: Analysis import pandas as pd df = pd.DataFrame(data) df.describe() ``` **Prototyping**: ```python # Cell: Quick test result = api.fetch(url) # No await! print(result) # Iterate quickly without async boilerplate ``` **Teaching**: ```python # Student-friendly code def process_data(source): data = source.fetch() # Looks sync return analyze(data) # Later: Reveal it's async print(f"fetch is async: {asyncio.iscoroutinefunction(source.fetch)}") ``` --- ## 📊 Comparison | Approach | Notebook Experience | Production Ready | Learning Curve | |----------|-------------------|-----------------|----------------| | **asyncio.run()** | Verbose | Yes | High | | **IPython await** | Better | Partial | Medium | | **SmartAsync** | Clean | Transition | Low | | **Sync-only** | Cleanest | Limited | Lowest | SmartAsync offers best notebook experience with async capability. --- ## 🎯 Success Metrics Your notebook approach is successful when: - Students/users don't ask about await - Examples are concise and clear - Easy to copy-paste and modify - Runs top-to-bottom reliably - Can transition to production code - Teaching goals achieved --- ## 💡 Teaching Strategy **Lesson 1: Use it** - Just call methods - Focus on what it does - No async mention **Lesson 2: Reveal** - Show it's async underneath - Explain why async is useful - Keep using without await **Lesson 3: Transition** - Show native async/await - Explain when needed - Compare approaches **Lesson 4: Production** - When to use each approach - Real-world patterns - Best practices --- **Next Steps**: - See [01: Sync App → Async Libraries](01-sync-app-async-libs.md) for similar simple interface - Check [03: Testing Async Code](03-testing-async-code.md) for testing async code simply