تبني هذه الصفحة برنامجًا يستخدم حزمة npm من JavaScript وحزمة PyPI من Python، في عملية واحدة.
| المتطلب | الطريقة |
|---|---|
| Python | elide setup python؛ ويسرد elide info اللغة python تحت Languages |
| الاستدعاءات بين اللغات | --interop في كل تشغيل؛ لا يوجد إعداد مقابل في ملف البيان |
| حزم npm | dependencies.npm في elide.pkl، ثم elide install --ecosystems= |
| حزم PyPI | بيئة افتراضية لـ Python 3.13، تُحدَّد باستخدام VIRTUAL_ENV |
إعداد المشروع
// elide.pkl
amends "elide:project.pkl"
name = "poly"
dependencies {
npm { packages { "pretty-ms@9.3.1" } }
pypi { packages { "humanize==4.12.3" } }
}elide install --ecosystems=npmيثبّت الأمر elide install دون خيارات تبعيات Maven فقط. ولا يثبّت Elide حزم PyPI: إذ ينتهي
elide install --ecosystems=pypi بالرمز 2 والرسالة pypi installs are not available in this build. احتفظ بكتلة
pypi سجلًّا للتبعيات، وثبّت الحزم باستخدام pip من Python 3.13 في بيئة افتراضية:
python3.13 -m venv .venv
.venv/bin/pip install humanize==4.12.3
export VIRTUAL_ENV=$PWD/.venvيحمّل Elide الحزم من $VIRTUAL_ENV/lib/python3.13/site-packages. تعمل الحزم المكتوبة بلغة Python الخالصة، ولا تُحمَّل
بعض وحدات الامتداد المكتوبة بلغة C (راجع Python).
كتابة البرنامج
# report.py
import humanize
def size(n):
return humanize.naturalsize(n)
def summarize(files):
total = sum(f.bytes for f in files)
return {"count": len(files), "total": humanize.naturalsize(total)}// app.mjs
import prettyMs from "pretty-ms";
import report from "./report.py";
const files = [
{ name: "build.log", bytes: 1_500_000, ageMs: 172_800_000 },
{ name: "test.log", bytes: 32_000, ageMs: 5_400_000 },
];
for (const f of files) {
console.log(`${f.name}: ${report.size(f.bytes)}, ${prettyMs(f.ageMs)} old`);
}
const summary = report.summarize(files);
console.log(`${summary.count} files, ${summary.total}`);elide --interop run app.mjsbuild.log: 1.5 MB, 2d old
test.log: 32.0 kB, 1h 30m old
2 files, 1.5 MBالتصدير الافتراضي لملف Python هو وحدته؛ استورده من نقطة دخول .mjs. وهذان خطآن شائعان:
| الناقص | الخطأ |
|---|---|
--interop | Error: Cannot import 'report. |
VIRTUAL_ENV | ModuleNotFoundError: No module named 'humanize' |
تمرير القيم
# shapes.py
def label(order):
return f"{order.item} x{order.qty}"
def doubled(prices):
return [p * 2 for p in prices]
def config():
return {"region": "eu", "retries": 3}
def apply(fn, value):
return fn(value)
def fail():
raise ValueError("bad input")// values.mjs
import shapes from "./shapes.py";
console.log(shapes.label({ item: "bolt", qty: 4 }));
console.log(shapes.doubled([1, 2.5, 3]).map((n) => n + 1));
const config = shapes.config();
console.log(config.region, config.get("retries"));
console.log(JSON.stringify(Object.fromEntries(config.items())));
console.log(shapes.apply((s) => s.toUpperCase(), "shout"));
console.log(shapes.apply((v) => v, null), shapes.apply((v) => v, undefined));elide --interop run values.mjsbolt x4
(3)[3, 6, 7]
eu 3
{"region":"eu","retries":3}
SHOUT
null undefined| القيمة | من JavaScript إلى Python | من Python إلى JavaScript |
|---|---|---|
| الأعداد والسلاسل النصية والقيم المنطقية | قيم أصلية | قيم أصلية |
null، undefined / None | None، وتعود دون تغيير | null |
كائن / dict | تُقرأ الحقول بوصفها سمات (order.item)؛ ويرمي order["item"] الخطأ TypeError | تُقرأ المفاتيح بالصيغة d.key أو d["key"] أو d.get("key")؛ وترى Object.keys و in و JSON.stringify توابع القاموس لا مفاتيحه. حوّله باستخدام Object.. |
مصفوفة / list | قابلة للتكرار والفهرسة، ويعمل len() | قيمة Array.isArray هي true؛ وتعمل map وعامل النشر (spread) و Array.from |
| دالة | قابلة للاستدعاء | قابلة للاستدعاء |
استدعاء JavaScript من Python
تقيّم الوحدة elide شيفرة JavaScript وتعيد قيمتها:
# calls.py
from elide import js
slug = js("(s) => s.trim().toLowerCase().replaceAll(' ', '-')")
print(slug(" Hello Polyglot World "))
point = js("({ x: 1, y: 2, tags: ['a', 'b'] })")
print(point.x + point.y, point.tags[0], len(point.tags))
print(sorted(js("[3, 1, 2]")))
try:
js("JSON.parse('{oops')")
except RuntimeError as e:
print("caught:", e)
js("Promise.resolve(42)").then(lambda v: print("resolved:", v))elide --interop python calls.pyhello-polyglot-world
3 a 2
[1, 2, 3]
caught: JSException: SyntaxError: Unexpected token o in JSON at position 1
resolved: 42معالجة الأخطاء
يصل استثناء Python إلى JavaScript بوصفه Error تكون قيمة name فيه هي صنف الاستثناء، ويصل خطأ JavaScript إلى
Python بوصفه RuntimeError. ويطبع الخطأ غير الملتقط مكدسًا واحدًا يمتد عبر اللغتين:
// errors.mjs
import shapes from "./shapes.py";
try {
shapes.fail();
} catch (e) {
console.log(e.name, "|", e.message);
}
shapes.apply((x) => {
throw new RangeError(`bad value ${x}`);
}, 7);elide --interop run errors.mjsValueError | ValueError: bad input
RangeError: bad value 7
at :=> (errors.mjs:10:9)
at apply (shapes.py:11:12)
at :module:eval (errors.mjs:9:1)ينتهي البرنامج بالرمز 1.
استدعاء الشيفرة غير المتزامنة
| من | يعمل | لا يعمل |
|---|---|---|
| JavaScript يستدعي Python | استدعاء غلاف متزامن يشغّل asyncio.run(...) | يعيد await على روتين Python المشترك الروتين نفسه دون تشغيله |
| Python يحمل وعد JavaScript | promise.then(callback) | يرمي await promise الخطأ TypeError: object polyglot. |
# rates.py
import asyncio
async def fetch_rate(code):
await asyncio.sleep(0.01)
return {"EUR": 0.92, "GBP": 0.79}[code]
def rate(code):
return asyncio.run(fetch_rate(code))
def when_ready(promise, done):
promise.then(lambda value: done(f"python saw {value}"))// rates.mjs
import rates from "./rates.py";
console.log("rate:", rates.rate("EUR"));
const total = new Promise((resolve) => setTimeout(() => resolve(7), 10));
rates.when_ready(total, (msg) => console.log(msg));
await total;elide --interop run rates.mjsrate: 0.92
python saw 7يحجب asyncio.run حلقة أحداث JavaScript حتى ينتهي الروتين المشترك. ولا تتوفر خيوط Python تحت --interop.
Java و Kotlin
يشغّل الأمر elide run Hello.kt شيفرة Kotlin وحدها؛ ولا تستطيع JavaScript و Python استدعاءها. ويفشل استيرادها:
import hello from "./Hello.kt";TypeError: Unsupported file extension: 'file:/path/to/Hello.kt'راجع أيضًا اللغات والتشغيل البيني و Python و مثبّت npm.