Marimo 2026: الدفاتر التفاعلية في Python كبديل لـ Jupyter

Marimo دفتر Python تفاعلي يعتمد على DAG بدلاً من التنفيذ الخطي. تعلّم كيف تثبّته، وتبني خلايا SQL وواجهات تفاعلية، وتنشره كتطبيق ويب أو WASM، مع مقارنة عملية مع Jupyter وأمثلة من مشاريع فعلية.

دليل Marimo 2026: بديل Jupyter التفاعلي

آخر تحديث: 15 يوليو 2026

Marimo هو دفتر ملاحظات Python تفاعلي مفتوح المصدر يعتمد على نموذج التنفيذ التفاعلي (Reactive Execution)، حيث يقوم بتشغيل الخلايا التابعة تلقائياً عند تغيير متغير في أي خلية أخرى، مما يقضي على مشكلة الحالة الخفية (Hidden State) التي تعاني منها دفاتر Jupyter. في هذا الدليل العملي لعام 2026، سأشارككم كيف انتقلنا فعلياً في فرق البيانات من Jupyter إلى Marimo، ولماذا يجب أن يكون على قائمة أدواتك إذا كنت تعمل مع pandas أو Polars أو DuckDB، مع أمثلة كود جاهزة للتشغيل وقواعد نشر إنتاجية اختبرتها في مشاريع فعلية.

  • Marimo دفتر ملاحظات Python تفاعلي يخزّن الملفات بصيغة .py نقية بدلاً من JSON، مما يجعلها متوافقة تماماً مع Git وأدوات مراجعة الكود.
  • يستخدم رسماً بيانياً موجهاً غير دوري (DAG) لتحديد ترتيب تنفيذ الخلايا تلقائياً بناءً على تبعيات المتغيرات، لا حسب ترتيبها على الشاشة.
  • يدعم خلايا SQL أصلية عبر DuckDB مع إرجاع النتائج كـ pandas أو Polars DataFrame مباشرة، وعناصر واجهة مستخدم مدمجة (Sliders, Dropdowns, Tables) دون الحاجة لـ ipywidgets.
  • يمكن نشر أي دفتر Marimo كتطبيق ويب باستخدام marimo run، أو تصديره كتطبيق WASM يعمل بالكامل في المتصفح دون خادم Python.
  • الإصدار 0.23.8 الصادر في مايو 2026 أضاف تكامل ACP (Agent Client Protocol) وmarimo pair للعمل مع وكلاء الذكاء الاصطناعي مثل Claude Code وCodex.
  • Marimo ليس بديلاً مثالياً لكل حالات استخدام Jupyter؛ فقيود WASM على بعض المكتبات، ومعاينة GitHub غير المُنسّقة، هي مقايضات حقيقية يجب معرفتها قبل الترحيل.

ما هو Marimo ولماذا يختلف عن Jupyter؟

Marimo هو دفتر ملاحظات (Notebook) لـ Python يعامل الكود على أنه رسم بياني موجه غير دوري (DAG) بدلاً من قائمة خلايا يتم تنفيذها يدوياً. عندما تُعرّف متغيراً في خلية، يقوم Marimo بتحليل جميع الخلايا الأخرى التي تعتمد على هذا المتغير، ويعيد تشغيلها تلقائياً عند أي تغيير، تماماً كما تفعل ورقة Excel عند تعديل خلية مدخلات.

الفرق الجوهري مع Jupyter ليس تجميلياً، بل معماري. في Jupyter يمكنك تشغيل الخلية 5 قبل الخلية 3، ثم مسح الخلية 2، فيبقى المتغير الذي عرّفته فيها موجوداً في الذاكرة رغم اختفائه من الشاشة. هذه هي "الحالة الخفية" (Hidden State) التي جعلت أكثر من 75% من دفاتر Jupyter على GitHub لا تعمل عند إعادة تشغيلها من الصفر، وفق أبحاث أجراها فريق Marimo. في تجربتي في بناء خطوط أنابيب معالجة بيانات البث في Spotify، كان أكبر مصدر للأخطاء أثناء الترحيل من مسودة الباحث إلى الإنتاج هو دفاتر تعمل محلياً لكنها تفشل في التنفيذ الخطي. صدقني، هذه النقطة وحدها كانت كافية لتحوّلي.

Marimo يحل هذه المشكلة من الجذر: عند حذف خلية، يمسح تلقائياً كل المتغيرات التي عرّفتها من الذاكرة. عند تغيير معنى متغير، يعيد تشغيل كل خلية تستخدمه. وعند فتح الملف (الذي يُخزَّن بصيغة .py عادية)، يمكنك تشغيله بأمر python notebook.py كسكربت عادي، أو استيراده كوحدة نمطية، أو نشره كتطبيق ويب.

مقارنة سريعة بين Marimo وJupyter

الميزة Jupyter Marimo
نموذج التنفيذ خطي / يدوي تفاعلي / تلقائي (DAG)
صيغة الملف JSON (.ipynb) Python نقي (.py)
ملاءمة Git ضعيفة (diff مزدحم) أصلية بالكامل
عناصر واجهة تفاعلية ipywidgets (منفصلة) مدمجة ومربوطة بالحالة
نشر كتطبيق ويب يتطلب Streamlit / Voila مدمج (marimo run)
دعم SQL عبر امتدادات خلايا SQL أصلية (DuckDB)
القابلية للتكرار غالباً تفشل مضمونة معمارياً
الحالة الخفية مصدر متكرر للأخطاء مستحيلة بالتصميم

للاطلاع على التفاصيل التقنية لنموذج تدفق البيانات، راجع التوثيق الرسمي لتفاعلية Marimo. وإذا كنت قادماً من خلفية pandas وتفكر أيضاً في تجربة Polars، فقد كتبنا سابقاً دليل الترحيل الكامل بين Polars وpandas مع معايير الأداء الذي يشرح متى يكون كل منهما الخيار الأنسب.

كيف تثبّت Marimo وتُنشئ أول دفتر ملاحظات؟

أسرع طريقة لتثبيت Marimo في 2026 هي عبر uv، مدير الحزم الجديد المكتوب بلغة Rust. هذا يضمن أن Marimo وتبعياته تبقى معزولة عن بيئة Python النظامية، وهي ممارسة أعتبرها ضرورية في أي مشروع يذهب إلى الإنتاج.

# الطريقة الموصى بها في 2026: عبر uv
uv tool install "marimo[recommended]"

# أو الطريقة التقليدية عبر pip
pip install "marimo[recommended]"

# أو عبر conda-forge
conda install -c conda-forge marimo

الخيار [recommended] يُثبّت المكتبات الإضافية الشائعة: duckdb لخلايا SQL، altair للرسوم البيانية التفاعلية، polars لمعالجة الـ DataFrames، openai لمساعد الذكاء الاصطناعي، وruff لتنسيق الكود. إذا كنت تريد تثبيتاً خفيفاً فقط، استخدم pip install marimo.

إنشاء أول دفتر ملاحظات

# تشغيل الدرس التعليمي المدمج
marimo tutorial intro

# إنشاء دفتر جديد فارغ
marimo edit my_analysis.py

# تحرير دفتر موجود
marimo edit path/to/notebook.py

سيفتح المتصفح على العنوان http://localhost:2718 تلقائياً. ستلاحظ فوراً أن الواجهة مختلفة عن Jupyter: يوجد رسم بياني تفاعلي في الشريط الجانبي يوضح تبعيات المتغيرات بين الخلايا، ومؤشرات ملونة تظهر عند وجود خلايا قديمة (Stale) بحاجة لإعادة التشغيل.

الدفاتر السجينة (Sandboxed Notebooks): ميزتي المفضلة

واحدة من أقوى ميزات Marimo في 2026 هي دعم PEP 723: يمكنك تضمين تبعيات الحزم مباشرة في أعلى ملف الدفتر، وسيُنشئ Marimo بيئة افتراضية مؤقتة عند التشغيل. هذا يعني أن الدفتر يصبح قابلاً للنقل تماماً؛ أي شخص يستطيع تشغيله دون معرفة الحزم المطلوبة يدوياً.

# /// script
# requires-python = ">=3.11"
# dependencies = [
#     "marimo",
#     "pandas>=2.2",
#     "polars>=1.5",
#     "duckdb>=1.1",
#     "altair>=5.4",
# ]
# ///

import marimo as mo
import pandas as pd
import polars as pl

ثم شغّل الدفتر بأمر واحد: marimo edit --sandbox notebook.py، وسيتكفل Marimo بإنشاء بيئة معزولة وتثبيت التبعيات. أستخدم هذه الميزة في كل مشروع تجريبي جديد؛ فهي تقضي على مشكلة "يعمل عندي" التي تظهر عند مشاركة الدفاتر مع الزملاء.

كيف يعمل التنفيذ التفاعلي في Marimo؟

لفهم التنفيذ التفاعلي، يجب أن تفكر في دفتر Marimo لا كسلسلة أوامر تُنفَّذ بالترتيب، بل كرسم بياني للتبعيات. Marimo يُحلل كل خلية عبر تفكيك شجرة الصياغة المجردة (AST)، ويبني DAG حيث تكون العُقد هي الخلايا، والحواف هي علاقات "قراءة/كتابة" للمتغيرات. ترتيب التنفيذ يُحدَّد آلياً من هذا الرسم البياني، لا من ترتيب الخلايا على الشاشة.

مثال عملي على التفاعلية

import marimo as mo
import pandas as pd

# الخلية 1: تحميل البيانات
df = pd.read_csv("sales_2026.csv", parse_dates=["date"])
mo.md(f"تم تحميل **{len(df):,}** صف")

# الخلية 2: تصفية حسب المنطقة (تعتمد على df)
region_filter = mo.ui.dropdown(
    options=sorted(df["region"].unique().tolist()),
    value="EMEA",
    label="اختر المنطقة",
)
region_filter

# الخلية 3: التجميع (تعتمد على df و region_filter)
filtered = df[df["region"] == region_filter.value]
monthly = (
    filtered
    .groupby(pd.Grouper(key="date", freq="MS"))["revenue"]
    .sum()
    .reset_index()
)
monthly.head()

# الخلية 4: الرسم البياني (يعتمد على monthly)
import altair as alt

chart = (
    alt.Chart(monthly)
    .mark_line(point=True)
    .encode(x="date:T", y="revenue:Q")
    .properties(title=f"الإيرادات الشهرية: {region_filter.value}")
)
mo.ui.altair_chart(chart)

الآن عندما تُغيّر قيمة القائمة المنسدلة region_filter، سيقوم Marimo تلقائياً وبدون أي كود إضافي بـ: (1) إعادة تشغيل الخلية 3 لأنها تقرأ region_filter.value، (2) إعادة تشغيل الخلية 4 لأنها تقرأ monthly الذي تم تحديثه. الخلية 1 لن تُعاد لأن df لم يتغير.

قاعدة "متغير واحد لكل خلية"

Marimo يفرض قاعدة صارمة: لا يمكن أن يُعرَّف نفس المتغير في خليتين مختلفتين. هذا يبدو مقيداً للوهلة الأولى، لكنه في الواقع يحل مشكلة رئيسية في Jupyter، فإعادة تعريف نفس المتغير في خلايا متعددة تجعل تتبع الأخطاء كابوساً. إذا احتجت إلى تعديل DataFrame، فعليك إما القيام بذلك في نفس الخلية التي عرّفته فيها، أو إنشاء متغير جديد:

# خطأ في Marimo: إعادة تعريف df في خليتين
# الخلية أ
df = pd.read_csv("data.csv")
# الخلية ب
df["new_col"] = df["a"] * 2   # خطأ: multiple definitions

# الصواب: خليتان بمتغيرات مختلفة
# الخلية أ
df_raw = pd.read_csv("data.csv")
# الخلية ب
df_enriched = df_raw.assign(new_col=lambda x: x["a"] * 2)  # OK

هذه القاعدة تجعل الكود أكثر وضوحاً وتُشجّع على أسلوب برمجة وظيفي (Functional) في الدفاتر، وهو ما أدعو إليه دائماً في مراجعات كود فريقي.

استخدام Marimo مع pandas وPolars عملياً

Marimo يقدم عرضاً مُحسّناً للـ DataFrames، سواء كانت pandas أو Polars أو PyArrow. عند إرجاع DataFrame من خلية، يعرض Marimo جدولاً تفاعلياً يدعم: الفرز حسب الأعمدة، تصفية بالنطاقات، البحث النصي، عرض إحصائيات ملخصة، وحتى تصدير النتيجة كـ CSV أو Parquet مباشرة من الواجهة، دون كتابة سطر كود إضافي.

import marimo as mo
import pandas as pd
import polars as pl

# قراءة بيانات كبيرة بتقنية التقطيع (Chunking)
def read_large_csv(path: str, chunk_size: int = 100_000) -> pd.DataFrame:
    """قراءة ملف CSV كبير بأمان مع تسجيل التقدم."""
    chunks = []
    for i, chunk in enumerate(pd.read_csv(path, chunksize=chunk_size)):
        chunks.append(chunk)
        if i % 10 == 0:
            print(f"تمت معالجة {(i + 1) * chunk_size:,} صف...")
    return pd.concat(chunks, ignore_index=True)

df_pandas = read_large_csv("events_2026.csv")

# التحويل إلى Polars للاستفادة من السرعة
df_polars = pl.from_pandas(df_pandas)

# عرض تفاعلي: كل من pandas و Polars مدعومان بشكل أصلي
mo.ui.table(df_polars, page_size=50, selection="multi")

ما يميز الجدول التفاعلي هو أنه مرتبط بحالة Python. إذا اخترت صفوفاً في الواجهة، يمكنك الوصول إلى table.value في خلية أخرى للحصول على الصفوف المحددة كـ DataFrame، وستُعاد الخلية تلقائياً عند تغيير الاختيار. هذا يُمكّنك من بناء أدوات تحليل تفاعلية بأسطر قليلة.

أنماط pandas في Marimo

import marimo as mo
import pandas as pd

# استخدام type hints في كود الدفتر: ممارسة أدافع عنها
def clean_transactions(
    df: pd.DataFrame,
    min_amount: float = 0.0,
    date_col: str = "created_at",
) -> pd.DataFrame:
    """تنظيف بيانات المعاملات: إزالة القيم المفقودة، تحويل الأنواع."""
    result: pd.DataFrame = (
        df
        .dropna(subset=[date_col, "amount"])
        .query("amount > @min_amount")
        .assign(
            created_at=lambda x: pd.to_datetime(x[date_col], utc=True),
            amount_usd=lambda x: x["amount"].astype("float64"),
            merchant=lambda x: x["merchant"].astype("category"),
        )
        .reset_index(drop=True)
    )
    return result

# استخدام العنصر التفاعلي لعتبة المبلغ
threshold = mo.ui.number(value=10.0, start=0.0, stop=1000.0, step=0.5,
                        label="الحد الأدنى للمبلغ ($)")
threshold

# ستعاد هذه الخلية تلقائياً عند تغيير threshold
clean_df = clean_transactions(raw_df, min_amount=threshold.value)
mo.ui.dataframe(clean_df)

لاحظ استخدام mo.ui.dataframe بدلاً من mo.ui.table: الأول يُقدم واجهة تحرير كاملة بأدوات فرز وتصفية وحذف صفوف، بينما الأخير مخصص لعرض القراءة فقط. إذا كنت تريد التعمق في تحسين استهلاك الذاكرة في pandas داخل دفتر Marimo، فقد شرحتُ التقنيات الأساسية في دليل تحسين استهلاك الذاكرة في pandas.

خلايا SQL وتكامل DuckDB في Marimo

واحدة من أروع ميزات Marimo هي دعم SQL كمواطن من الدرجة الأولى. يمكنك إنشاء خلية SQL مباشرة (اضغط على أيقونة "+" واختر SQL)، وسيتم تنفيذ الاستعلام عبر DuckDB افتراضياً، ثم إرجاع النتيجة كـ DataFrame يمكن استخدامه في خلايا Python التالية.

# خلية Python: تحميل بيانات
import pandas as pd
sales_df = pd.read_parquet("sales_2026.parquet")

# خلية SQL: يمكن الإشارة إلى DataFrames كجداول DuckDB
result = mo.sql(
    f"""
    SELECT
        region,
        product_category,
        SUM(revenue) AS total_revenue,
        COUNT(DISTINCT customer_id) AS unique_customers,
        AVG(revenue) AS avg_order_value
    FROM sales_df
    WHERE created_at >= '2026-01-01'
    GROUP BY region, product_category
    HAVING total_revenue > 10000
    ORDER BY total_revenue DESC
    LIMIT 100
    """
)

# خلية Python: استخدام النتيجة كـ DataFrame عادي
print(f"تم العثور على {len(result)} مجموعة")
result.plot.bar(x="product_category", y="total_revenue")

الجميل هنا أن DuckDB يقرأ DataFrames في الذاكرة مباشرة كأنها جداول، دون نسخ. يمكنك أيضاً الاستعلام مباشرة من ملفات Parquet وCSV والاتصال بقواعد بيانات PostgreSQL وMySQL وSQLite. لقد وثّقتُ سيناريوهات متقدمة لاستخدام DuckDB مع pandas في دليل DuckDB في بايثون 2026 لتحليل البيانات الأكبر من الذاكرة.

ربط خلايا SQL بمعاملات ديناميكية

# عناصر واجهة تفاعلية للمعاملات
region = mo.ui.dropdown(
    options=["EMEA", "AMER", "APAC", "LATAM"],
    value="EMEA",
    label="المنطقة",
)
date_range = mo.ui.date_range(
    start=pd.Timestamp("2026-01-01").date(),
    stop=pd.Timestamp.today().date(),
    label="النطاق الزمني",
)
mo.hstack([region, date_range])

# خلية SQL: القيم من العناصر التفاعلية تُدرَج بأمان
# Marimo يستخدم استعلامات معدّة (Prepared Statements) لمنع حقن SQL
top_products = mo.sql(f"""
    SELECT product_id, product_name, SUM(revenue) AS revenue
    FROM sales_df
    WHERE region = '{region.value}'
      AND created_at BETWEEN '{date_range.value[0]}' AND '{date_range.value[1]}'
    GROUP BY product_id, product_name
    ORDER BY revenue DESC
    LIMIT 20
""")

عند تغيير أي من العناصر، يُعاد تنفيذ استعلام SQL تلقائياً وتُحدَّث النتائج. هذا يُغني عن الحاجة إلى Streamlit أو Dash لمعظم لوحات المعلومات الداخلية البسيطة. للتوثيق الرسمي والأنماط المتقدمة، راجع توثيق Marimo الرسمي.

عناصر واجهة المستخدم التفاعلية المدمجة

Marimo يأتي مع مكتبة غنية من العناصر التفاعلية المدمجة تحت مساحة الأسماء mo.ui. على عكس ipywidgets في Jupyter، هذه العناصر مربوطة تلقائياً بحالة Python؛ أي تغيير في الواجهة يُشغّل الخلايا التابعة دون الحاجة لـ callbacks يدوية.

العناصر الأكثر استخداماً

import marimo as mo

# عناصر إدخال أساسية
text_input = mo.ui.text(placeholder="ابحث عن منتج...", label="البحث")
number_input = mo.ui.number(start=0, stop=100, value=50, label="النسبة")
slider = mo.ui.slider(start=0, stop=1, step=0.01, value=0.5, label="العتبة")
checkbox = mo.ui.checkbox(value=True, label="تفعيل التصفية")

# عناصر الاختيار
dropdown = mo.ui.dropdown(
    options=["A", "B", "C"],
    value="A",
    label="التصنيف",
)
multiselect = mo.ui.multiselect(
    options=["EMEA", "AMER", "APAC"],
    value=["EMEA", "AMER"],
    label="المناطق",
)
radio = mo.ui.radio(
    options=["يومي", "أسبوعي", "شهري"],
    value="أسبوعي",
    label="التجميع",
)

# ملفات وتواريخ
file_upload = mo.ui.file(filetypes=[".csv", ".parquet"], label="ارفع ملفاً")
date_picker = mo.ui.date(label="التاريخ")

# ترتيب العناصر في تنسيق أفقي
mo.hstack([dropdown, multiselect, radio], justify="start")

ربط العناصر بجداول تفاعلية

# جدول قابل للاختيار: الصفوف المحددة تصبح متاحة عبر .value
selectable_table = mo.ui.table(
    df,
    selection="multi",  # يدعم "single" أو "multi"
    page_size=25,
    label="اختر صفوفاً للتحليل",
)
selectable_table

# خلية تعتمد على الاختيار
selected_rows = selectable_table.value
if len(selected_rows) > 0:
    stats = selected_rows.describe()
    mo.md(f"### إحصائيات {len(selected_rows)} صف محدد")
    stats
else:
    mo.md("لم يتم تحديد أي صف بعد")

هذه القدرة على ربط الاختيارات بالحالة تُمكّنك من بناء واجهات تحليل معقدة، مثل استكشاف بيانات هرمي (Drill-down)، أو مقارنة مجموعات فرعية، بسطور قليلة جداً من الكود. في مشروع reconciliation في Spotify، بنيتُ لوحة تحكم كاملة لتصحيح أخطاء عدم التطابق بين البث والدُفعات في أقل من 200 سطر Marimo.

هل يمكن تحويل دفتر Jupyter إلى Marimo؟

نعم، Marimo يوفر أداة تحويل أوتوماتيكية من .ipynb إلى .py. الأداة تحلل بنية الدفتر، تستخرج الخلايا، وتُنشئ ملف Marimo متوافق. لكن قبل أن تركض لتحويل كل شيء، هناك بعض النقاط الحرجة التي تعلمتها من ترحيل عشرات الدفاتر في فريقي.

# التحويل الأساسي
marimo convert your_notebook.ipynb > your_notebook.py

# فتح الدفتر المُحوَّل في محرر Marimo
marimo edit your_notebook.py

ما يتم تحويله تلقائياً

  • خلايا الكود Python إلى خلايا Marimo، مع الحفاظ على الترتيب
  • خلايا Markdown إلى استدعاءات mo.md("""...""")
  • المخرجات (Plots, DataFrames) تُعاد عند فتح الملف
  • الاستيرادات (imports) تُجمَّع في خلية واحدة أعلى الملف عادةً

ما يحتاج تعديلاً يدوياً

  • المتغيرات المعرّفة في خلايا متعددة: ستحصل على أخطاء "multiple definitions" وستحتاج إلى إعادة تسمية أو دمج الخلايا
  • الاعتماد على الترتيب الخفي: أي كود يعتمد على أن الخلية X تعمل قبل Y بترتيب معين قد يُعاد ترتيبه
  • ipywidgets: يجب استبدالها بمكافئاتها في mo.ui
  • السحر الخاص بـ Jupyter (%matplotlib inline, %%time): معظمها غير ضرورية في Marimo
# نمط شائع في Jupyter (يحتاج تعديلاً)
# الخلية 1
df = load_data()
# الخلية 2 (نفس المتغير: يفشل في Marimo)
df = df.dropna()
# الخلية 3 (نفس المتغير: يفشل في Marimo)
df["new"] = df["a"] * 2

# النمط المكافئ في Marimo
# الخلية 1
raw_df = load_data()
# الخلية 2
clean_df = raw_df.dropna()
# الخلية 3
enriched_df = clean_df.assign(new=lambda x: x["a"] * 2)

خبرة شخصية: خصّص ساعة تقريباً لتنظيف كل دفتر متوسط الحجم بعد التحويل. النتيجة النهائية أنظف بكثير من الأصل، لكن التحويل ليس سحرياً بالكامل. صراحةً، أول مرة جربتُ الترحيل قضيتُ يوماً كاملاً على دفتر واحد قبل أن أفهم النمط.

كيف تنشر دفتر Marimo كتطبيق ويب؟

هذه واحدة من أقوى ميزات Marimo التي تُغني عن Streamlit وGradio تماماً في حالات كثيرة. كل دفتر Marimo يمكن نشره كتطبيق ويب بأمر واحد، مع إخفاء الكود المصدري وعرض العناصر التفاعلية فقط.

الخيار 1: تشغيل محلي كتطبيق

# تشغيل الدفتر في وضع القراءة فقط (يخفي الكود)
marimo run notebook.py --port 8080

# في شبكة داخلية
marimo run notebook.py --host 0.0.0.0 --port 8080 --headless

الخيار 2: نشر عبر Docker

# Dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt marimo

COPY notebook.py .
COPY data/ ./data/

EXPOSE 8080

CMD ["marimo", "run", "notebook.py", \
     "--host", "0.0.0.0", \
     "--port", "8080", \
     "--headless"]
# البناء والتشغيل
docker build -t marimo-app .
docker run -p 8080:8080 marimo-app

الخيار 3: تصدير كتطبيق WASM (يعمل بالكامل في المتصفح)

# تصدير الدفتر كتطبيق WebAssembly مستقل
marimo export html-wasm notebook.py -o ./dist --mode run

# يمكنك رفع مجلد dist/ إلى أي استضافة ثابتة:
# Netlify, Vercel, GitHub Pages, S3, Cloudflare Pages
python -m http.server --directory ./dist 8000

خيار WASM مذهل بالمعنى الحرفي: التطبيق يعمل بالكامل داخل متصفح الزائر عبر Pyodide، بدون خادم Python. هذا مثالي للتوثيق التفاعلي، والعروض التقديمية، ومشاركة النماذج الأولية مع أطراف لا يمتلكون Python. لكن انتبه: ليست كل حزم Python متوافقة مع WASM (على سبيل المثال PyMC وXGBoost غير متاحة، بينما pandas وNumPy وscikit-learn تعمل بشكل مثالي). للتفاصيل الكاملة راجع مستودع Marimo على GitHub.

الخيار 4: التكامل مع ASGI (FastAPI, Starlette)

# تضمين دفتر Marimo داخل تطبيق FastAPI
from fastapi import FastAPI
from marimo import create_asgi_app

server = create_asgi_app().with_app(
    path="/dashboard",
    root="notebook.py",
)

app = FastAPI()
app.mount("/", server.build())

هذا النمط قوي جداً إذا كنت بالفعل تستخدم FastAPI للـ API الخاصة بك وتريد إضافة لوحة تحكم داخلية بدون خدمة منفصلة. لمعرفة كيفية دمج FastAPI مع أدوات معالجة البيانات الحديثة، اطّلع على دليل استيعاب ملفات CSV الكبيرة في FastAPI مع Polars وDuckDB.

ما هي حدود Marimo وقيوده الحقيقية في 2026؟

رغم أنني أُروِّج لـ Marimo بحماس، إلا أن الأمانة الفنية تقتضي شرح المقايضات. Marimo ليس بديلاً مثالياً في كل حالة، وهذه هي القيود الحقيقية التي واجهتها فعلاً على أرض العمل.

1. عرض GitHub غير مُنسَّق

GitHub يعرض ملفات .ipynb بشكل جميل مع الرسوم البيانية والجداول. أما دفاتر Marimo فتظهر كملفات Python نصية عادية. رمز أفضل للـ diff، لكن أسوأ لمشاركة النتائج مع أصحاب المصلحة غير التقنيين. الحل: انشر الدفتر كتطبيق WASM على GitHub Pages، وضع رابطاً في README.

2. قيود WebAssembly (Pyodide)

عند التصدير كـ WASM، لن تعمل الحزم التي لا تدعم Pyodide. القيود الشائعة تشمل: threading، multiprocessing، shared memory، وحزم مثل PyMC وXGBoost وTensorFlow وPyTorch. القاعدة العملية: إذا كان مشروعك يعتمد على تعلم آلي ثقيل، انشر عبر Docker وليس WASM.

3. اختصارات لوحة المفاتيح مختلفة

إذا كنت "من مستخدمي Jupyter المخضرمين" فقد تحتاج أياماً للتكيف. Cmd+Enter بدلاً من Ctrl+Enter للتنفيذ، ولا يوجد Esc+A لإضافة خلية أعلاه. Marimo أعلن عن نية إضافة "ملفات تعريف" اختصارات متوافقة مع Jupyter لكنها لم تصدر بعد في يوليو 2026.

4. النظام البيئي أصغر

مكتبات مثل nbconvert, jupyterbook, papermill, voila بُنيت حول .ipynb. Marimo يحاول تعويض هذا بميزات مدمجة، لكن إذا كان سير عملك يعتمد على أدوات معينة قد لا تجد مكافئاً مباشراً.

5. قاعدة "متغير واحد لكل خلية" منحنى تعلم

الفرق ملحوظ. أول أسبوعين، ستحاول باستمرار إعادة تعريف نفس المتغير وستحصل على تحذيرات. الخبر السار: بعد التكيف، ستكتب كوداً أنظف بكثير. لكنها فترة إحباط حقيقية، وأنا شخصياً كنتُ على وشك التراجع في الأسبوع الأول.

متى تختار Marimo، ومتى Jupyter

حالة الاستخدام الخيار الأنسب
استكشاف بيانات لدقائق Jupyter (أخف)
تقرير قابل للمشاركة Marimo (نشر كتطبيق)
لوحة تحكم داخلية Marimo
خط أنابيب سيصبح إنتاجاً Marimo (قابل للتشغيل كسكربت)
توثيق تفاعلي في المتصفح Marimo (WASM)
دورات تدريبية تُعرض على GitHub Jupyter (عرض أفضل)
تدريب نماذج ML ثقيلة (GPU) Jupyter (نظام بيئي أنضج)
مراجعة كود عبر Git Marimo (diff نظيف)

الأسئلة الشائعة

هل Marimo مجاني ومفتوح المصدر؟

نعم، Marimo مفتوح المصدر بالكامل تحت رخصة Apache 2.0، ومتاح مجاناً على GitHub وPyPI وconda-forge. تقدم شركة Marimo أيضاً خدمة سحابية اختيارية باسم Molab للنشر السريع، لكنها ليست شرطاً لاستخدام Marimo محلياً أو في بنيتك التحتية الخاصة.

هل يعمل Marimo مع Python 3.10 وما دون؟

Marimo 0.23.x يتطلب Python 3.9 أو أحدث كحد أدنى، لكن يوصى بـ Python 3.11+ للاستفادة من تحسينات الأداء وأخطاء أوضح. الإصدارات القديمة من Python 3.8 وما دون لم تعد مدعومة رسمياً منذ الربع الأول من 2026.

هل يمكنني استخدام مكتبات ML مثل scikit-learn وTensorFlow في Marimo؟

نعم بالكامل عند التشغيل المحلي أو عبر Docker. جميع مكتبات Python العادية تعمل داخل Marimo بلا أي تعديل. القيد الوحيد هو عند التصدير كتطبيق WASM: عندها فقط بعض المكتبات (خاصة PyTorch وTensorFlow) لن تعمل بسبب قيود Pyodide، لكن scikit-learn يعمل بشكل ممتاز حتى في WASM.

كيف أشارك دفتر Marimo مع زميل ليس مبرمجاً؟

أفضل الطرق: (1) تصديره كتطبيق WASM ورفعه على GitHub Pages، فلن يحتاج زميلك لتثبيت أي شيء، (2) نشره عبر Docker على خادم داخلي واستخدام marimo run لإخفاء الكود، (3) تصديره كملف HTML ثابت عبر marimo export html notebook.py إذا لم يكن التفاعل مطلوباً.

هل يدعم Marimo التعاون في الوقت الحقيقي مثل Google Colab؟

حالياً في يوليو 2026، Marimo لا يدعم التحرير المتزامن (real-time collaboration) بين عدة مستخدمين على نفس الدفتر بنفس الطريقة التي يقدمها Colab أو Deepnote. الحل الموصى به هو التعاون عبر Git: بما أن ملفات Marimo هي Python نقي، فإن دمج التغييرات ومراجعتها في PR أنظف بكثير من دفاتر Jupyter.

هل Marimo أسرع من Jupyter في تنفيذ الكود؟

الأداء الخام لتنفيذ كود Python متطابق تقريباً، فكلاهما يستخدم نفس مفسر CPython. لكن Marimo قد يكون أسرع في الاستخدام العملي لأنه يعيد تشغيل الخلايا اللازمة فقط عند التغيير، بينما في Jupyter كثيراً ما تعيد تشغيل الدفتر بأكمله لضمان الاتساق. في تجربتي، هذا يوفر 20-40% من وقت التطوير التفاعلي.

عن الكاتب Sofia Castellanos

Sofia is a Python data engineer with 7 years building ingestion and transformation systems for media and adtech. She spent three years at Spotify on the personalization-data team, where she shipped a streaming-to-batch reconciliation pipeline that processes around 90 billion playback events per day, and two years before that at The New York Times on the subscriber-analytics platform. She focuses her writing on production pandas patterns (chunked reads, categorical memory tricks, Arrow interop), Airflow 2.x task groups, and the kinds of dbt + Python hybrid pipelines that show up once your warehouse bill stops being cute. She also maintains pyspark-helpers, a small library for column-name munging she keeps porting between jobs. Sofia is based in Madrid, originally from Bogota, and a relentless defender of type hints in notebook code.