akhaliq's picture
akhaliq HF Staff
Deploy from anycoder
72d6344 verified
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)** πŸš€