Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import traceback | |
| import inspect | |
| def analyze_gradio_error(): | |
| """ | |
| Analyze and explain the Gradio error related to Markdown postprocessing. | |
| Returns a properly formatted markdown string to avoid the list error. | |
| """ | |
| error_message = """ | |
| ## π οΈ Gradio Error Analysis & Fix | |
| ### **Error Summary** | |
| AttributeError: 'list' object has no attribute 'expandtabs' | |
| **Location**: `gradio/components/markdown.py` β `inspect.cleandoc()` | |
| ### **Root Cause** | |
| Gradio's `Markdown` component expects a **single string**, but received a **list of strings**. | |
| When `inspect.cleandoc()` tries to process the list with `.expandtabs()`, it fails. | |
| ### **Common Scenarios Causing This Error:** | |
| 1. **Function returning list instead of string:** | |
| # β WRONG - Returns list | |
| def bad_function(): | |
| return ["Line 1", "Line 2"] # List breaks Markdown! | |
| # β CORRECT - Return single string | |
| def good_function(): | |
| return "Line 1\\nLine 2" # Single string with newlines | |
| 2. **Multiple gr.Markdown outputs:** | |
| # β WRONG | |
| with gr.Row(): | |
| out1 = gr.Markdown() | |
| out2 = gr.Markdown() | |
| demo([fn], outputs=[out1, out2]) # Returns list! | |
| # β CORRECT | |
| output_md = gr.Markdown() # Single output | |
| ### **Quick Fixes:** | |
| **Fix 1: Convert list to string** | |
| def safe_markdown_output(items): | |
| if isinstance(items, list): | |
| return "\\n".join(str(item) for item in items) | |
| return str(items) | |
| **Fix 2: Use HTML instead of Markdown** | |
| gr.HTML(value="<div>...</div>") # No postprocessing issues | |
| **Fix 3: Single Markdown output** | |
| # Always return ONE string, not list | |
| output = gr.Markdown() | |
| ### **Debug Steps:** | |
| 1. `print(type(your_function_output))` β Should be `<class 'str'>` | |
| 2. Use `gr.Textbox()` temporarily to inspect raw output | |
| 3. Check if function returns tuple/list unexpectedly | |
| ### **Prevention:** | |
| def safe_markdown(text): | |
| """Always returns valid markdown string""" | |
| if isinstance(text, (list, tuple)): | |
| text = "\\n".join(str(x) for x in text) | |
| if not isinstance(text, str): | |
| text = str(text) | |
| return text.strip() | |
| **π Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder)** | |
| """ | |
| return error_message | |
| def test_your_function(code_input): | |
| """Test user code safely and return markdown-friendly output""" | |
| try: | |
| # Create a safe exec environment | |
| local_vars = {} | |
| exec(code_input, {"gr": gr}, local_vars) | |
| # Try to find a function and test it | |
| if 'fn' in local_vars: | |
| fn = local_vars['fn'] | |
| test_input = "test" | |
| result = fn(test_input) | |
| # Convert ANY output to safe markdown string | |
| safe_output = "" | |
| if isinstance(result, (list, tuple)): | |
| safe_output = "\\n".join(str(x) for x in result) | |
| elif hasattr(result, '__iter__') and not isinstance(result, str): | |
| safe_output = "\\n".join(str(x) for x in list(result)[:10]) | |
| else: | |
| safe_output = str(result) | |
| return f""" | |
| β **Test Successful!** | |
| **Input**: `{test_input}` | |
| **Output Type**: `{type(result).__name__}` | |
| **Output Preview**: | |
| {safe_output[:1000]}... | |
| **Status**: β Safe for Gradio Markdown component! | |
| """ | |
| else: | |
| return "β No `fn` function found. Define a function named `fn` in your code." | |
| except Exception as e: | |
| tb = traceback.format_exc() | |
| return f""" | |
| β **Error in your code:** | |
| {str(e)[:500]}... | |
| **Full Traceback**: | |
| {tb[:1500]}... | |
| """ | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(), | |
| title="Gradio Error Fix - Markdown List Issue", | |
| css=""" | |
| .gradio-container {max-width: 1200px !important;} | |
| .status-good {background: #d4edda; color: #155724; padding: 10px;} | |
| .status-bad {background: #f8d7da; color: #721c24; padding: 10px;} | |
| """ | |
| ) as demo: | |
| gr.Markdown( | |
| """ | |
| # π **Gradio Error Fix: 'list' object has no attribute 'expandtabs'** | |
| **The #1 cause**: Your function returns a **list** to a **Markdown** component! | |
| > **Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder)** | |
| """, | |
| elem_classes="header" | |
| ) | |
| with gr.Tabs(): | |
| with gr.TabItem("π Error Analysis", icon="π"): | |
| analyze_output = gr.Markdown(value="Loading analysis...") | |
| analyze_btn = gr.Button("π Refresh Analysis", variant="secondary") | |
| analyze_btn.click(analyze_gradio_error, outputs=analyze_output) | |
| with gr.TabItem("π§ͺ Test Your Function", icon="β‘"): | |
| gr.Markdown(""" | |
| ## Test your `fn` function here: | |
| ```python | |
| def fn(input_text): | |
| # Your code here | |
| return "Hello World" # NOT a list! | |
| """) | |
| code_input = gr.Textbox( | |
| label="Your function code", | |
| lines=10, | |
| placeholder="def fn(input_text):\n return f'Hello {input_text}'", | |
| show_label=True | |
| ) | |
| test_btn = gr.Button("π Test Function", variant="primary") | |
| test_output = gr.Markdown() | |
| test_btn.click( | |
| test_your_function, | |
| inputs=code_input, | |
| outputs=test_output | |
| ) | |
| with gr.TabItem("β Quick Fix Templates", icon="β¨"): | |
| gr.Markdown(""" | |
| ## Copy-paste these fixes: | |
| ### **Fix 1: Safe Markdown Output** | |
| ```python | |
| def safe_markdown_output(data): | |
| if isinstance(data, list): | |
| return "\\n".join(str(x) for x in data) | |
| return str(data) | |
| ### **Fix 2: Complete Interface** | |
| ```python | |
| import gradio as gr | |
| def fn(input_text): | |
| # Your logic here | |
| return "Result as STRING" | |
| demo = gr.Interface( | |
| fn, | |
| "text", | |
| "markdown" # Single output! | |
| ) | |
| demo.launch() | |
| ### **Fix 3: Blocks Pattern** | |
| ```python | |
| with gr.Blocks() as demo: | |
| inp = gr.Textbox() | |
| out = gr.Markdown() # Single component! | |
| def fn(x): | |
| return safe_markdown_output(your_result) | |
| inp.submit(fn, inp, out) | |
| """) | |
| demo.launch() | |
| This Gradio app directly addresses your error by: | |
| 1. **π Explains the exact cause** - Markdown component receiving lists | |
| 2. **π§ͺ Tests your code safely** - Converts any output to markdown-safe strings | |
| 3. **β Provides copy-paste fixes** - Working templates you can use immediately | |
| 4. **π Self-diagnosing** - Tests if your function output is safe for Gradio | |
| **Key Fix**: Always ensure functions return **single strings** to `gr.Markdown()`, never lists! The app automatically converts lists to newline-separated strings. | |
| **Built with [anycoder](https://huggingface.co/spaces/akhaliq/anycoder)** π |