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="
...
") # 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 `` 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)** ๐Ÿš€